# Code Guidelines for WhatsHooked

## General Principles

- Write clean, idiomatic Go code following standard conventions
- Use meaningful variable and function names
- Keep functions small and focused on a single responsibility
- Document exported functions, types, and packages
- Handle errors explicitly, never ignore them
- Use context.Context for cancellation and timeout handling

## Project Structure

```
whatshooked/
├── cmd/                    # Command-line entry points
│   ├── server/            # HTTP server command
│   └── cli/               # CLI tools
├── pkg/                    # Public packages
│   ├── auth/              # Authentication & authorization
│   ├── api/               # API endpoints
│   ├── cache/             # Caching layer
│   ├── config/            # Configuration management
│   ├── events/            # Event system
│   ├── eventlogger/       # Event logging
│   ├── handlers/          # HTTP handlers
│   ├── hooks/             # Webhook management
│   ├── logging/           # Structured logging
│   ├── storage/           # Database storage layer
│   ├── utils/             # Utility functions
│   ├── webserver/         # Web server with ResolveSpec
│   ├── whatsapp/          # WhatsApp integration
│   └── whatshooked/       # Core application logic
└── tooldoc/               # Tool & library documentation
```

## Naming Conventions

### Packages
- Use lowercase, single-word package names
- Use descriptive names that reflect the package's purpose
- Avoid generic names like `util` or `common` (use `utils` with specific subdirectories if needed)

### Files
- Use snake_case for file names: `user_service.go`, `auth_middleware.go`
- Test files: `user_service_test.go`
- Keep related functionality in the same file

### Variables & Functions
- Use camelCase for private: `userService`, `handleRequest`
- Use PascalCase for exported: `UserService`, `HandleRequest`
- Use descriptive names: prefer `userRepository` over `ur`
- Boolean variables should be prefixed: `isValid`, `hasPermission`, `canAccess`

### Constants
- Use PascalCase for exported: `DefaultTimeout`
- Use camelCase for private: `defaultTimeout`
- Group related constants together

### Interfaces
- Name interfaces with -er suffix when appropriate: `Reader`, `Writer`, `Handler`
- Use descriptive names: `UserRepository`, `AuthService`

## Error Handling

```go
// Wrap errors with context
if err != nil {
    return fmt.Errorf("failed to load user: %w", err)
}

// Check specific errors
if errors.Is(err, sql.ErrNoRows) {
    return nil, ErrUserNotFound
}

// Custom error types
type ValidationError struct {
    Field   string
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("%s: %s", e.Field, e.Message)
}
```

## Logging

Use zerolog for structured logging:

```go
import "github.com/rs/zerolog/log"

log.Info().
    Str("user_id", userID).
    Msg("User logged in")

log.Error().
    Err(err).
    Str("operation", "database_query").
    Msg("Failed to query database")
```

## Context Usage

Always pass context as the first parameter:

```go
func ProcessRequest(ctx context.Context, userID string) error {
    // Check for cancellation
    select {
    case <-ctx.Done():
        return ctx.Err()
    default:
    }
    
    // Pass context to downstream calls
    user, err := userRepo.GetByID(ctx, userID)
    if err != nil {
        return err
    }
    
    return nil
}
```

## Testing

- Write table-driven tests
- Use descriptive test names: `TestUserService_Create_WithValidData_Success`
- Mock external dependencies
- Aim for high coverage of business logic
- Use t.Run for subtests

```go
func TestUserService_Create(t *testing.T) {
    tests := []struct {
        name    string
        input   *User
        wantErr bool
    }{
        {
            name: "valid user",
            input: &User{Name: "John", Email: "john@example.com"},
            wantErr: false,
        },
        {
            name: "missing email",
            input: &User{Name: "John"},
            wantErr: true,
        },
    }
    
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            service := NewUserService()
            err := service.Create(tt.input)
            if (err != nil) != tt.wantErr {
                t.Errorf("Create() error = %v, wantErr %v", err, tt.wantErr)
            }
        })
    }
}
```

## Database Operations

- Use transactions for multiple related operations
- Always use prepared statements
- Handle NULL values properly
- Use meaningful struct tags

```go
type User struct {
    ID        string    `gorm:"primaryKey" json:"id"`
    Name      string    `gorm:"not null" json:"name"`
    Email     string    `gorm:"uniqueIndex;not null" json:"email"`
    CreatedAt time.Time `json:"created_at"`
    UpdatedAt time.Time `json:"updated_at"`
}
```

## ResolveSpec Integration

When using ResolveSpec:
- Register all models in the registry
- Use schema.table format: "public.users", "core.accounts"
- Implement hooks for auth and validation
- Use lifecycle hooks for audit logging

## API Design

- Use RESTful conventions
- Return appropriate HTTP status codes
- Include meaningful error messages
- Version your APIs: `/api/v1/users`
- Document all endpoints

## Security

- Never log sensitive data (passwords, tokens, etc.)
- Validate all input
- Use parameterized queries
- Implement rate limiting
- Use HTTPS in production
- Sanitize user input
- Implement proper CORS policies

## Dependencies

- Keep dependencies minimal
- Pin versions in go.mod
- Regularly update dependencies
- Document why each dependency is needed

## Documentation

- Document all exported functions, types, and packages
- Use godoc format
- Include examples in documentation
- Keep README.md up to date
- Document configuration options

## Comments

```go
// Package auth provides authentication and authorization functionality.
package auth

// User represents a system user.
type User struct {
    ID string
}

// Authenticate verifies user credentials and returns a token.
// Returns ErrInvalidCredentials if authentication fails.
func Authenticate(ctx context.Context, username, password string) (string, error) {
    // Implementation
}
```

## Performance

- Use connection pools for databases
- Implement caching where appropriate
- Avoid N+1 queries
- Use batch operations when possible
- Profile critical paths
- Set appropriate timeouts

## Git Workflow

- Write clear commit messages
- Keep commits atomic and focused
- Use conventional commits format
- Create feature branches
- Run tests before committing
- Review your own changes before pushing
