refactor(API): ✨ Relspect integration
This commit is contained in:
259
tooldoc/CODE_GUIDELINES.md
Normal file
259
tooldoc/CODE_GUIDELINES.md
Normal file
@@ -0,0 +1,259 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user