858 lines
19 KiB
Markdown
858 lines
19 KiB
Markdown
# Contributing to Veza Backend API
|
|
|
|
Thank you for your interest in contributing to Veza Backend API! This guide will help you get started and ensure your contributions align with our standards.
|
|
|
|
## Table of Contents
|
|
|
|
1. [Code of Conduct](#code-of-conduct)
|
|
2. [Getting Started](#getting-started)
|
|
3. [Development Workflow](#development-workflow)
|
|
4. [Code Standards](#code-standards)
|
|
5. [Testing](#testing)
|
|
6. [Documentation](#documentation)
|
|
7. [Pull Requests](#pull-requests)
|
|
8. [Code Review Process](#code-review-process)
|
|
9. [Commit Guidelines](#commit-guidelines)
|
|
10. [Project Structure](#project-structure)
|
|
11. [Common Tasks](#common-tasks)
|
|
12. [Getting Help](#getting-help)
|
|
|
|
## Code of Conduct
|
|
|
|
### Our Principles
|
|
|
|
1. **Stability over Velocity**: Every change improves robustness (tests, types, lint, docs)
|
|
2. **Unidirectional Flow**: Need → Design → Implementation → Test → Doc → PR → Review → Merge
|
|
3. **Full Traceability**: All decisions = ADR (Architecture Decision Record), atomic commits with Conventional Commits
|
|
4. **Integrated Security**: No secret leaks, mandatory secret scanners, verified dependencies
|
|
5. **Controlled Autonomy**: AI agents work in background, always via PR + checklists, mandatory human review
|
|
|
|
### Expected Behavior
|
|
|
|
- Be respectful and inclusive
|
|
- Welcome newcomers and help them learn
|
|
- Focus on constructive feedback
|
|
- Respect different viewpoints and experiences
|
|
|
|
### Unacceptable Behavior
|
|
|
|
- Harassment or discriminatory language
|
|
- Personal attacks
|
|
- Trolling or inflammatory comments
|
|
- Publishing others' private information
|
|
|
|
## Getting Started
|
|
|
|
### Prerequisites
|
|
|
|
- **Go** 1.23 or higher
|
|
- **PostgreSQL** 12+ (for database)
|
|
- **Redis** (optional, for caching and rate limiting)
|
|
- **Docker** (optional, for containerized development)
|
|
- **Git** 2.30+
|
|
|
|
### Initial Setup
|
|
|
|
1. **Fork and Clone**
|
|
```bash
|
|
# Fork the repository on GitHub
|
|
git clone https://github.com/your-username/veza-backend-api.git
|
|
cd veza-backend-api
|
|
```
|
|
|
|
2. **Add Upstream Remote**
|
|
```bash
|
|
git remote add upstream https://github.com/veza/veza-backend-api.git
|
|
```
|
|
|
|
3. **Install Dependencies**
|
|
```bash
|
|
make deps
|
|
# or manually
|
|
go mod download
|
|
go mod tidy
|
|
```
|
|
|
|
4. **Set Up Environment**
|
|
```bash
|
|
# Copy example environment file
|
|
cp .env.example .env
|
|
|
|
# Edit .env with your configuration
|
|
# Minimum required:
|
|
# - DATABASE_URL
|
|
# - JWT_SECRET (min 32 characters)
|
|
# - APP_ENV
|
|
```
|
|
|
|
5. **Verify Installation**
|
|
```bash
|
|
# Build the application
|
|
make build
|
|
|
|
# Run tests
|
|
make test
|
|
|
|
# Check code quality
|
|
make lint
|
|
make vet
|
|
```
|
|
|
|
## Development Workflow
|
|
|
|
### Branching Model
|
|
|
|
We follow a feature branch workflow:
|
|
|
|
- `main`: Always stable, always deployable
|
|
- `develop`: Integration branch (optional)
|
|
- Feature branches: `feat/<feature-name>`
|
|
- Bug fix branches: `fix/<bug-description>`
|
|
- Documentation branches: `docs/<description>`
|
|
- Refactoring branches: `refactor/<description>`
|
|
|
|
### Creating a Branch
|
|
|
|
```bash
|
|
# Update main branch
|
|
git checkout main
|
|
git pull upstream main
|
|
|
|
# Create feature branch
|
|
git checkout -b feat/your-feature-name
|
|
|
|
# Or use the shorthand
|
|
git checkout -b feat/your-feature-name upstream/main
|
|
```
|
|
|
|
### Branch Naming Conventions
|
|
|
|
- `feat/`: New features
|
|
- `fix/`: Bug fixes
|
|
- `docs/`: Documentation changes
|
|
- `refactor/`: Code refactoring
|
|
- `test/`: Test additions or changes
|
|
- `chore/`: Maintenance tasks
|
|
- `perf/`: Performance improvements
|
|
|
|
Examples:
|
|
- `feat/auth-refresh-tokens`
|
|
- `fix/jwt-uuid-mismatch`
|
|
- `refactor/user-service-cleanup`
|
|
- `docs/api-documentation-update`
|
|
|
|
## Code Standards
|
|
|
|
### Go Code Style
|
|
|
|
#### Formatting
|
|
|
|
- Use `gofmt` (automatically applied)
|
|
- Use `goimports` for import organization
|
|
- Run `make format` before committing
|
|
|
|
```bash
|
|
# Format code
|
|
make format
|
|
|
|
# Or manually
|
|
go fmt ./...
|
|
goimports -w .
|
|
```
|
|
|
|
#### Naming Conventions
|
|
|
|
- **Packages**: lowercase, single word, no underscores
|
|
- **Exported functions/types**: PascalCase
|
|
- **Unexported functions/types**: camelCase
|
|
- **Constants**: PascalCase for exported, camelCase for unexported
|
|
- **Interfaces**: PascalCase, often end with `-er` (e.g., `Reader`, `Writer`)
|
|
|
|
```go
|
|
// Good
|
|
package user
|
|
|
|
type UserService struct {
|
|
repo UserRepository
|
|
}
|
|
|
|
func (s *UserService) GetByID(id uuid.UUID) (*User, error) {
|
|
// ...
|
|
}
|
|
|
|
// Bad
|
|
package user_service
|
|
|
|
type user_service struct {
|
|
repo user_repository
|
|
}
|
|
|
|
func (s *user_service) get_by_id(id uuid.UUID) (*user, error) {
|
|
// ...
|
|
}
|
|
```
|
|
|
|
#### Code Organization
|
|
|
|
- Keep functions small and focused (single responsibility)
|
|
- Prefer composition over inheritance
|
|
- Use interfaces for abstraction
|
|
- Avoid deep nesting (max 3-4 levels)
|
|
- Return errors explicitly, don't ignore them
|
|
|
|
```go
|
|
// Good
|
|
func (s *UserService) GetByID(ctx context.Context, id uuid.UUID) (*User, error) {
|
|
if id == uuid.Nil {
|
|
return nil, errors.New("user ID cannot be nil")
|
|
}
|
|
|
|
user, err := s.repo.FindByID(ctx, id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get user: %w", err)
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
// Bad
|
|
func (s *UserService) GetByID(ctx context.Context, id uuid.UUID) (*User, error) {
|
|
user, _ := s.repo.FindByID(ctx, id) // Error ignored!
|
|
return user, nil
|
|
}
|
|
```
|
|
|
|
#### Error Handling
|
|
|
|
- Always handle errors explicitly
|
|
- Wrap errors with context using `fmt.Errorf` with `%w`
|
|
- Use sentinel errors for expected error conditions
|
|
- Return errors, don't log them (let the caller decide)
|
|
|
|
```go
|
|
// Good
|
|
var ErrUserNotFound = errors.New("user not found")
|
|
|
|
func (s *UserService) GetByID(ctx context.Context, id uuid.UUID) (*User, error) {
|
|
user, err := s.repo.FindByID(ctx, id)
|
|
if err != nil {
|
|
if errors.Is(err, ErrUserNotFound) {
|
|
return nil, ErrUserNotFound
|
|
}
|
|
return nil, fmt.Errorf("failed to get user %s: %w", id, err)
|
|
}
|
|
return user, nil
|
|
}
|
|
|
|
// Bad
|
|
func (s *UserService) GetByID(ctx context.Context, id uuid.UUID) (*User, error) {
|
|
user, err := s.repo.FindByID(ctx, id)
|
|
if err != nil {
|
|
log.Printf("Error: %v", err) // Don't log here!
|
|
return nil, err
|
|
}
|
|
return user, nil
|
|
}
|
|
```
|
|
|
|
#### Context Usage
|
|
|
|
- Always accept `context.Context` as the first parameter
|
|
- Use context for cancellation, timeouts, and request-scoped values
|
|
- Don't store contexts in structs
|
|
|
|
```go
|
|
// Good
|
|
func (s *UserService) GetByID(ctx context.Context, id uuid.UUID) (*User, error) {
|
|
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
|
defer cancel()
|
|
|
|
user, err := s.repo.FindByID(ctx, id)
|
|
// ...
|
|
}
|
|
|
|
// Bad
|
|
type UserService struct {
|
|
ctx context.Context // Don't store context!
|
|
}
|
|
```
|
|
|
|
#### Comments and Documentation
|
|
|
|
- Document all exported functions, types, and constants
|
|
- Use complete sentences
|
|
- Start with the name of the thing being described
|
|
- Use `//` for comments, `/* */` for block comments (rarely)
|
|
|
|
```go
|
|
// UserService provides operations for managing users.
|
|
type UserService struct {
|
|
repo UserRepository
|
|
}
|
|
|
|
// GetByID retrieves a user by their unique identifier.
|
|
// It returns ErrUserNotFound if the user does not exist.
|
|
func (s *UserService) GetByID(ctx context.Context, id uuid.UUID) (*User, error) {
|
|
// ...
|
|
}
|
|
```
|
|
|
|
### Linting and Code Quality
|
|
|
|
#### Required Tools
|
|
|
|
- **golangci-lint**: Comprehensive Go linter
|
|
- **go vet**: Built-in Go static analysis
|
|
- **goimports**: Import organization
|
|
|
|
```bash
|
|
# Install golangci-lint
|
|
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
|
|
|
# Run linters
|
|
make lint
|
|
make vet
|
|
```
|
|
|
|
#### Common Issues to Avoid
|
|
|
|
1. **Unused imports**: Use `goimports` to clean up
|
|
2. **Unused variables**: Remove or use `_` to explicitly ignore
|
|
3. **Shadowed variables**: Use different names
|
|
4. **Error handling**: Always check and handle errors
|
|
5. **Race conditions**: Use proper synchronization
|
|
|
|
### Project Structure
|
|
|
|
```
|
|
veza-backend-api/
|
|
├── cmd/ # Application entry points
|
|
│ ├── modern-server/ # Main server
|
|
│ └── tools/ # Utility tools
|
|
├── internal/ # Private application code
|
|
│ ├── handlers/ # HTTP handlers
|
|
│ ├── services/ # Business logic
|
|
│ ├── repositories/ # Data access layer
|
|
│ ├── models/ # Data models
|
|
│ ├── dto/ # Data transfer objects
|
|
│ ├── middleware/ # HTTP middleware
|
|
│ ├── validators/ # Input validation
|
|
│ ├── errors/ # Error definitions
|
|
│ └── config/ # Configuration
|
|
├── pkg/ # Public library code
|
|
├── migrations/ # Database migrations
|
|
├── tests/ # Integration tests
|
|
├── docs/ # Documentation
|
|
├── scripts/ # Utility scripts
|
|
└── Makefile # Build automation
|
|
```
|
|
|
|
### Package Organization
|
|
|
|
- **`internal/`**: Private code, not importable by other projects
|
|
- **`pkg/`**: Public library code, importable by other projects
|
|
- **`cmd/`**: Application entry points
|
|
- Keep packages focused and cohesive
|
|
- Avoid circular dependencies
|
|
|
|
## Testing
|
|
|
|
### Test Requirements
|
|
|
|
- **All new features** must include tests
|
|
- **Bug fixes** must include regression tests
|
|
- **Test coverage** should be ≥ 80% for new code
|
|
- **Tests must pass** before submitting PR
|
|
|
|
### Test Structure
|
|
|
|
```go
|
|
package user_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestUserService_GetByID(t *testing.T) {
|
|
// Arrange
|
|
ctx := context.Background()
|
|
service := setupUserService(t)
|
|
user := createTestUser(t, ctx)
|
|
|
|
// Act
|
|
result, err := service.GetByID(ctx, user.ID)
|
|
|
|
// Assert
|
|
require.NoError(t, err)
|
|
assert.Equal(t, user.ID, result.ID)
|
|
assert.Equal(t, user.Email, result.Email)
|
|
}
|
|
```
|
|
|
|
### Test Types
|
|
|
|
1. **Unit Tests**: Test individual functions/methods
|
|
```bash
|
|
go test ./internal/services/...
|
|
```
|
|
|
|
2. **Integration Tests**: Test with real dependencies
|
|
```bash
|
|
go test -tags=integration ./tests/integration/...
|
|
```
|
|
|
|
3. **Race Detection**: Detect race conditions
|
|
```bash
|
|
go test -race ./...
|
|
```
|
|
|
|
### Test Best Practices
|
|
|
|
- Use table-driven tests for multiple scenarios
|
|
- Use `testify/assert` and `testify/require`
|
|
- Clean up test data (use `t.Cleanup()`)
|
|
- Use test helpers for common setup
|
|
- Mock external dependencies
|
|
|
|
```go
|
|
func TestUserService_GetByID_TableDriven(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
userID uuid.UUID
|
|
wantErr bool
|
|
errType error
|
|
}{
|
|
{
|
|
name: "valid user",
|
|
userID: validUserID,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "user not found",
|
|
userID: uuid.New(),
|
|
wantErr: true,
|
|
errType: ErrUserNotFound,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Test implementation
|
|
})
|
|
}
|
|
}
|
|
```
|
|
|
|
### Running Tests
|
|
|
|
```bash
|
|
# Run all tests
|
|
make test
|
|
|
|
# Run tests with coverage
|
|
make test-coverage
|
|
|
|
# Run tests with race detection
|
|
make test-race
|
|
|
|
# Run specific test
|
|
go test -v ./internal/services/user_service_test.go
|
|
|
|
# Run tests matching pattern
|
|
go test -v -run TestUserService
|
|
```
|
|
|
|
## Documentation
|
|
|
|
### Code Documentation
|
|
|
|
- Document all exported functions, types, and constants
|
|
- Use Go doc comments (start with the name)
|
|
- Include examples for complex functions
|
|
- Document error conditions
|
|
|
|
```go
|
|
// User represents a user in the system.
|
|
//
|
|
// Example:
|
|
// user := &User{
|
|
// ID: uuid.New(),
|
|
// Email: "user@example.com",
|
|
// }
|
|
type User struct {
|
|
ID uuid.UUID
|
|
Email string
|
|
}
|
|
|
|
// GetByID retrieves a user by ID.
|
|
//
|
|
// Returns ErrUserNotFound if the user does not exist.
|
|
func (s *UserService) GetByID(ctx context.Context, id uuid.UUID) (*User, error) {
|
|
// ...
|
|
}
|
|
```
|
|
|
|
### API Documentation
|
|
|
|
- Update Swagger/OpenAPI documentation for API changes
|
|
- Include request/response examples
|
|
- Document error responses
|
|
- Document authentication requirements
|
|
|
|
### README Updates
|
|
|
|
- Update README for significant changes
|
|
- Document new environment variables
|
|
- Update installation instructions if needed
|
|
- Add migration notes for breaking changes
|
|
|
|
## Pull Requests
|
|
|
|
### Before Creating a PR
|
|
|
|
1. **Update your branch**
|
|
```bash
|
|
git checkout main
|
|
git pull upstream main
|
|
git checkout feat/your-feature
|
|
git rebase main
|
|
```
|
|
|
|
2. **Run quality checks**
|
|
```bash
|
|
make format
|
|
make lint
|
|
make vet
|
|
make test
|
|
```
|
|
|
|
3. **Verify your changes**
|
|
- All tests pass
|
|
- Code compiles without errors
|
|
- No linting errors
|
|
- Documentation updated
|
|
|
|
### Creating a PR
|
|
|
|
1. **Push your branch**
|
|
```bash
|
|
git push origin feat/your-feature
|
|
```
|
|
|
|
2. **Create PR on GitHub**
|
|
- Use the PR template
|
|
- Fill in all sections
|
|
- Link related issues
|
|
- Add reviewers
|
|
|
|
3. **PR Title Format**
|
|
```
|
|
[CATEGORY] Brief description
|
|
|
|
Examples:
|
|
[FEAT] Add user profile endpoint
|
|
[FIX] Correct JWT token validation
|
|
[DOCS] Update API documentation
|
|
```
|
|
|
|
### PR Description Template
|
|
|
|
```markdown
|
|
## Description
|
|
Brief description of changes
|
|
|
|
## Type of Change
|
|
- [ ] Bug fix
|
|
- [ ] New feature
|
|
- [ ] Breaking change
|
|
- [ ] Documentation update
|
|
|
|
## Related Issues
|
|
Closes #123
|
|
|
|
## Changes Made
|
|
- Change 1
|
|
- Change 2
|
|
|
|
## Testing
|
|
- [ ] Unit tests added/updated
|
|
- [ ] Integration tests added/updated
|
|
- [ ] Manual testing performed
|
|
|
|
## Checklist
|
|
- [ ] Code follows style guidelines
|
|
- [ ] Self-review completed
|
|
- [ ] Comments added for complex code
|
|
- [ ] Documentation updated
|
|
- [ ] No new warnings generated
|
|
- [ ] Tests added and passing
|
|
- [ ] Breaking changes documented
|
|
```
|
|
|
|
### PR Best Practices
|
|
|
|
- Keep PRs focused and small (< 500 lines ideally)
|
|
- One logical change per PR
|
|
- Include tests for new features
|
|
- Update documentation
|
|
- Respond to review comments promptly
|
|
- Rebase on main if conflicts arise
|
|
|
|
## Code Review Process
|
|
|
|
### Review Criteria
|
|
|
|
1. **Functionality**: Does it work as intended?
|
|
2. **Code Quality**: Follows style guidelines?
|
|
3. **Tests**: Adequate test coverage?
|
|
4. **Documentation**: Properly documented?
|
|
5. **Performance**: No obvious performance issues?
|
|
6. **Security**: No security vulnerabilities?
|
|
|
|
### Review Guidelines
|
|
|
|
- Be constructive and respectful
|
|
- Focus on code, not the person
|
|
- Explain the "why" behind suggestions
|
|
- Approve when satisfied
|
|
- Request changes when needed
|
|
|
|
### Responding to Reviews
|
|
|
|
- Address all comments
|
|
- Ask for clarification if needed
|
|
- Make requested changes
|
|
- Re-request review when ready
|
|
- Thank reviewers for their time
|
|
|
|
## Commit Guidelines
|
|
|
|
### Conventional Commits
|
|
|
|
We follow [Conventional Commits](https://www.conventionalcommits.org/) specification:
|
|
|
|
```
|
|
<type>[optional scope]: <description>
|
|
|
|
[optional body]
|
|
|
|
[optional footer(s)]
|
|
```
|
|
|
|
### Commit Types
|
|
|
|
- `feat`: New feature
|
|
- `fix`: Bug fix
|
|
- `docs`: Documentation changes
|
|
- `style`: Code style changes (formatting, etc.)
|
|
- `refactor`: Code refactoring
|
|
- `test`: Test additions/changes
|
|
- `chore`: Maintenance tasks
|
|
- `perf`: Performance improvements
|
|
- `ci`: CI/CD changes
|
|
|
|
### Commit Examples
|
|
|
|
```bash
|
|
feat(auth): add refresh token endpoint
|
|
|
|
fix(user): correct email validation regex
|
|
|
|
docs(api): update authentication documentation
|
|
|
|
refactor(service): simplify user service logic
|
|
|
|
test(user): add tests for user creation
|
|
```
|
|
|
|
### Commit Best Practices
|
|
|
|
- Write clear, descriptive commit messages
|
|
- Use present tense ("add" not "added")
|
|
- Keep commits atomic (one logical change)
|
|
- Reference issues in commit message
|
|
- Don't commit generated files
|
|
|
|
```bash
|
|
# Good
|
|
feat(auth): add refresh token endpoint
|
|
|
|
Implements refresh token generation and validation.
|
|
Adds /api/v1/auth/refresh endpoint.
|
|
|
|
Closes #123
|
|
|
|
# Bad
|
|
fix stuff
|
|
```
|
|
|
|
## Common Tasks
|
|
|
|
### Adding a New Endpoint
|
|
|
|
1. **Define DTOs** (`internal/dto/`)
|
|
```go
|
|
type CreateUserRequest struct {
|
|
Email string `json:"email" binding:"required,email"`
|
|
Username string `json:"username" binding:"required,min=3"`
|
|
}
|
|
```
|
|
|
|
2. **Create Handler** (`internal/handlers/`)
|
|
```go
|
|
func (h *UserHandler) CreateUser(c *gin.Context) {
|
|
var req CreateUserRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
RespondWithError(c, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
// ...
|
|
}
|
|
```
|
|
|
|
3. **Add Service Logic** (`internal/services/`)
|
|
```go
|
|
func (s *UserService) CreateUser(ctx context.Context, req *CreateUserRequest) (*User, error) {
|
|
// Business logic
|
|
}
|
|
```
|
|
|
|
4. **Register Route** (`cmd/modern-server/main.go` or router)
|
|
```go
|
|
api.POST("/users", userHandler.CreateUser)
|
|
```
|
|
|
|
5. **Add Tests**
|
|
```go
|
|
func TestUserHandler_CreateUser(t *testing.T) {
|
|
// Test implementation
|
|
}
|
|
```
|
|
|
|
6. **Update Documentation**
|
|
- Update Swagger annotations
|
|
- Update API documentation
|
|
|
|
### Adding a New Service
|
|
|
|
1. **Define Interface** (`internal/services/`)
|
|
```go
|
|
type ProductService interface {
|
|
CreateProduct(ctx context.Context, req *CreateProductRequest) (*Product, error)
|
|
GetProduct(ctx context.Context, id uuid.UUID) (*Product, error)
|
|
}
|
|
```
|
|
|
|
2. **Implement Service**
|
|
```go
|
|
type productService struct {
|
|
repo ProductRepository
|
|
}
|
|
|
|
func NewProductService(repo ProductRepository) ProductService {
|
|
return &productService{repo: repo}
|
|
}
|
|
```
|
|
|
|
3. **Add Tests**
|
|
```go
|
|
func TestProductService_CreateProduct(t *testing.T) {
|
|
// Test implementation
|
|
}
|
|
```
|
|
|
|
### Adding Database Migrations
|
|
|
|
1. **Create Migration File**
|
|
```bash
|
|
migrate create -ext sql -dir migrations -seq add_products_table
|
|
```
|
|
|
|
2. **Write Migration** (`migrations/XXXXXX_add_products_table.up.sql`)
|
|
```sql
|
|
CREATE TABLE products (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name VARCHAR(255) NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
```
|
|
|
|
3. **Write Rollback** (`migrations/XXXXXX_add_products_table.down.sql`)
|
|
```sql
|
|
DROP TABLE products;
|
|
```
|
|
|
|
4. **Test Migration**
|
|
```bash
|
|
migrate -path ./migrations -database "$DATABASE_URL" up
|
|
migrate -path ./migrations -database "$DATABASE_URL" down
|
|
```
|
|
|
|
## Getting Help
|
|
|
|
### Resources
|
|
|
|
- **Documentation**: See `docs/` directory
|
|
- **API Documentation**: `/swagger/index.html` when server is running
|
|
- **Architecture Guide**: `docs/ARCHITECTURE.md`
|
|
- **Development Guide**: `docs/DEVELOPMENT_SETUP_GUIDE.md`
|
|
- **Troubleshooting**: `docs/TROUBLESHOOTING_GUIDE.md`
|
|
|
|
### Communication Channels
|
|
|
|
- **GitHub Issues**: For bug reports and feature requests
|
|
- **GitHub Discussions**: For questions and discussions
|
|
- **Pull Requests**: For code-related questions
|
|
|
|
### Asking Questions
|
|
|
|
When asking for help, include:
|
|
|
|
1. **What you're trying to do**
|
|
2. **What you've tried**
|
|
3. **Error messages** (if any)
|
|
4. **Relevant code snippets**
|
|
5. **Environment details** (OS, Go version, etc.)
|
|
|
|
### Reporting Bugs
|
|
|
|
Use the bug report template:
|
|
|
|
```markdown
|
|
## Description
|
|
Brief description of the bug
|
|
|
|
## Steps to Reproduce
|
|
1. Step 1
|
|
2. Step 2
|
|
3. Step 3
|
|
|
|
## Expected Behavior
|
|
What should happen
|
|
|
|
## Actual Behavior
|
|
What actually happens
|
|
|
|
## Environment
|
|
- OS: [e.g., Linux, macOS, Windows]
|
|
- Go Version: [e.g., 1.23.0]
|
|
- Application Version: [e.g., 1.2.0]
|
|
|
|
## Additional Context
|
|
Any other relevant information
|
|
```
|
|
|
|
## Recognition
|
|
|
|
Contributors are recognized in:
|
|
|
|
- **README**: Contributors section
|
|
- **CHANGELOG**: Release notes
|
|
- **GitHub**: Contributors page
|
|
|
|
Thank you for contributing to Veza Backend API! 🚀
|
|
|