Contributing Guide¶
Last Updated: 2025-11-23 Difficulty: Beginner to Intermediate
Welcome to the ocmonica project! This guide will help you contribute effectively, whether you're fixing a bug, adding a feature, or improving documentation.
Table of Contents¶
- Code of Conduct
- Getting Started
- Development Setup
- Code Style
- Git Workflow
- Making Changes
- Pull Request Process
- Code Review Guidelines
- Git Hooks
- Release Process
- Communication
Code of Conduct¶
Our Standards¶
- Be respectful and considerate in all interactions
- Be collaborative and help others learn
- Be professional in code reviews and discussions
- Be patient with newcomers and questions
- Be constructive when providing feedback
Our Responsibilities¶
Project maintainers are responsible for:
- Clarifying standards of acceptable behavior
- Taking corrective action in response to inappropriate behavior
- Removing, editing, or rejecting contributions that don't align with this Code of Conduct
Reporting Issues¶
If you experience or witness unacceptable behavior, please report it by opening an issue or contacting the maintainers directly.
Getting Started¶
Prerequisites¶
Before you begin, ensure you have:
- Go 1.25.2+ installed (installation guide)
- Node.js 20+ installed (installation guide)
- Task installed (installation guide)
- Buf installed (installation guide)
- golangci-lint installed (installation guide)
- Git with SSH keys configured
- A GitHub account
Fork and Clone¶
- Fork the repository on GitHub
- Clone your fork locally:
- Add upstream remote:
- Verify remotes:
Initial Setup¶
# Install all dependencies and generate code
task setup
# Or step by step:
task install # Install Go dependencies
task web:install # Install Node.js dependencies
task proto:gen # Generate protobuf code
task config:init # Create config files
# Install git hooks
task hooks:install
Verify Setup¶
If all commands succeed, you're ready to contribute!
Development Setup¶
Editor Configuration¶
VS Code (Recommended)¶
Install these extensions:
- Go (golang.go)
- golangci-lint
- Prettier (esbenp.prettier-vscode)
- ESLint (dbaeumer.vscode-eslint)
- Buf (bufbuild.vscode-buf)
Settings (.vscode/settings.json):
{
"go.useLanguageServer": true,
"go.lintTool": "golangci-lint",
"go.lintOnSave": "workspace",
"editor.formatOnSave": true,
"[go]": {
"editor.defaultFormatter": "golang.go",
"editor.codeActionsOnSave": {
"source.organizeImports": "always"
}
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
GoLand / IntelliJ IDEA¶
- Enable golangci-lint integration:
- Preferences → Tools → Go Linter
- Enable "Run golangci-lint"
- Enable goimports on save:
- Preferences → Tools → File Watchers
- Add "goimports" watcher
- Set Go version to 1.25.2+:
- Preferences → Go → GOROOT
Environment Variables¶
Create a .env file (gitignored):
# Server
OCMONICA_SERVER__PORT=8080
OCMONICA_SERVER__HOST=localhost
# Database
OCMONICA_DATABASE__PATH=./data/ocmonica.db
# Storage
OCMONICA_STORAGE__BASE_PATH=./data/files
# JWT (development only - use external keys in production)
OCMONICA_JWT__GENERATE_KEYS=true
# Logging
OCMONICA_LOGGING__LEVEL=debug
OCMONICA_LOGGING__FORMAT=text
# Observability
OCMONICA_OBSERVABILITY__JAEGER__ENABLED=true
OCMONICA_OBSERVABILITY__JAEGER__ENDPOINT=http://localhost:14268/api/traces
Code Style¶
Go Code Standards¶
Naming Conventions¶
Public (exported):
type FileService struct {} // PascalCase
func (s *FileService) Upload() {} // PascalCase
var ErrNotFound = errors.New("...") // PascalCase
Private (unexported):
type fileRepository struct {} // camelCase
func (r *fileRepository) create() {} // camelCase
var errInvalidInput = errors.New("...") // camelCase
Receivers:
func (s *FileService) Method() {} // 1-2 letter abbreviation
func (fh *FileHandler) Handle() {} // Acronyms acceptable
Avoid stuttering:
// ❌ Wrong
package file
type FileService struct {} // file.FileService (stutters)
// ✅ Correct
package file
type Service struct {} // file.Service (clean)
Documentation¶
Required for all public types and functions:
// FileService handles file management operations.
// It coordinates between the repository layer and handlers,
// enforcing permissions and validating business rules.
type FileService struct {
repo repository.FileRepository
}
// Upload stores a new file in the system.
// It validates the filename, checks permissions, and stores the file
// content along with metadata.
//
// Returns ErrInvalidInput if the filename is invalid.
// Returns ErrPermissionDenied if the user lacks write permissions.
func (s *FileService) Upload(ctx context.Context, filename string, content io.Reader) (*models.File, error) {
// Implementation
}
Documentation style: - Start with the item name - Use complete sentences with periods - Explain what, not how (implementation details go in comments) - Document error conditions - Include usage examples for complex APIs
Import Organization¶
import (
// 1. Standard library (alphabetical)
"context"
"errors"
"fmt"
"time"
// 2. Third-party packages (alphabetical)
"connectrpc.com/connect"
"github.com/labstack/echo/v4"
"github.com/google/uuid"
// 3. Project packages (alphabetical)
"github.com/j-pye/ocmonica/internal/models"
"github.com/j-pye/ocmonica/internal/repository"
"github.com/j-pye/ocmonica/internal/service"
)
Error Handling¶
// Define sentinel errors
var (
ErrNotFound = errors.New("not found")
ErrInvalidInput = errors.New("invalid input")
)
// Wrap errors with context (use %w, not %v)
if err != nil {
return nil, fmt.Errorf("failed to upload file %s: %w", filename, err)
}
// Check errors with errors.Is
if errors.Is(err, repository.ErrNotFound) {
return connect.NewError(connect.CodeNotFound, err)
}
// Never ignore errors
result, err := doSomething()
if err != nil {
return fmt.Errorf("operation failed: %w", err)
}
TypeScript/React Code Standards¶
Naming Conventions¶
// Components: PascalCase
export function FileUpload() {}
// Functions: camelCase
function handleUpload() {}
// Constants: UPPER_SNAKE_CASE
const MAX_FILE_SIZE = 10 * 1024 * 1024;
// Interfaces/Types: PascalCase
interface FileMetadata {
name: string;
size: number;
}
Component Structure¶
// 1. Imports
import React, { useState } from 'react';
import { FileService } from '@/lib/api';
// 2. Types/Interfaces
interface FileUploadProps {
onComplete: (file: File) => void;
}
// 3. Component
export function FileUpload({ onComplete }: FileUploadProps) {
// Hooks first
const [file, setFile] = useState<File | null>(null);
// Event handlers
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
// ...
};
// Render
return (
// JSX
);
}
Formatting¶
Automated by git hooks:
- Go: goimports + go fmt
- TypeScript: prettier
- Protobuf: buf format
Manual formatting:
Git Workflow¶
Branching Strategy¶
We use GitHub Flow:
main (protected)
↓
feature/add-file-preview
bugfix/fix-auth-token
docs/update-contributing
chore/update-dependencies
Branch naming:
- feature/ - New features
- bugfix/ - Bug fixes
- docs/ - Documentation updates
- chore/ - Maintenance tasks
- refactor/ - Code refactoring
- test/ - Test additions/improvements
Branch naming rules:
- Use lowercase
- Use hyphens, not underscores
- Be descriptive but concise
- Reference issue number when applicable: feature/123-add-dark-mode
Commit Message Format¶
We follow Conventional Commits:
Types:
- feat: New feature
- fix: Bug fix
- docs: Documentation changes
- style: Code style changes (formatting, semicolons, etc.)
- refactor: Code refactoring
- test: Adding or updating tests
- chore: Maintenance tasks (dependencies, build, etc.)
- perf: Performance improvements
- ci: CI/CD changes
Examples:
# Feature
feat(files): add video playback with position tracking
Implements HTTP Range Request support for video streaming.
Users can now seek to any position in uploaded videos.
Closes #123
# Bug fix
fix(auth): prevent token refresh race condition
Multiple simultaneous refresh requests were creating duplicate tokens.
Now uses mutex to ensure single refresh at a time.
Fixes #456
# Documentation
docs(contributing): add git workflow section
# Chore
chore(deps): update dependencies to latest versions
Subject line: - Use imperative mood ("add" not "added") - Don't capitalize first letter - No period at the end - 50 characters or less
Body (optional): - Wrap at 72 characters - Explain what and why, not how - Reference issues and PRs
Commit Message Validation¶
Git hooks validate commit messages automatically. If validation fails:
# Example error
❌ Commit message validation failed:
- Subject must be in lowercase
- Subject must be 50 characters or less
- Type must be one of: feat, fix, docs, style, refactor, test, chore, perf, ci
To skip validation (not recommended):
Making Changes¶
Creating a Feature Branch¶
# Sync with upstream
git checkout main
git pull upstream main
# Create feature branch
git checkout -b feature/my-awesome-feature
# Push to your fork
git push -u origin feature/my-awesome-feature
Development Workflow¶
-
Write tests first (TDD approach):
-
Implement feature:
-
Run full test suite:
-
Check coverage:
-
Lint code:
-
Security scan:
Committing Changes¶
# Stage specific files
git add internal/service/my_feature.go
git add internal/service/my_feature_test.go
# Commit with conventional message
git commit -m "feat(service): add awesome new feature
Implements XYZ functionality with ABC approach.
Includes comprehensive test coverage.
Closes #123"
Git hooks will automatically:
- Format Go code with goimports and go fmt
- Lint Go code with golangci-lint
- Format TypeScript with prettier
- Lint TypeScript with eslint
- Format protobuf with buf format
- Lint protobuf with buf lint
- Validate commit message format
- Regenerate STATUS.md
Pushing Changes¶
Pull Request Process¶
Before Creating a PR¶
Checklist:
- [ ] All tests pass: task test
- [ ] Linting passes: task lint
- [ ] Security scan clean: task security:scan
- [ ] Code formatted: task fmt
- [ ] Coverage maintained or improved
- [ ] Documentation updated
- [ ] Commit messages follow convention
- [ ] Branch is up to date with main
Update branch with main:
git checkout main
git pull upstream main
git checkout feature/my-awesome-feature
git rebase main
git push origin feature/my-awesome-feature --force-with-lease
Creating the PR¶
- Go to your fork on GitHub
- Click "Compare & pull request"
- Fill out the PR template:
## Description
Brief description of what this PR does and why.
## Type of Change
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
## How Has This Been Tested?
Describe the tests you added/ran to verify your changes:
- [ ] Unit tests
- [ ] Integration tests
- [ ] Manual testing
## Checklist
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published
## Screenshots (if applicable)
Add screenshots to help explain your changes.
## Related Issues
Closes #123
Related to #456
- Request reviewers (maintainers will be notified automatically)
- Add labels (if you have permissions)
During Review¶
Responding to feedback:
-
Make requested changes:
-
Reply to comments:
- Be professional and constructive
- Ask for clarification if needed
- Explain your reasoning when disagreeing
-
Mark conversations as resolved when addressed
-
Update the PR:
- Keep the PR description updated
- Add notes about significant changes
- Re-request review after addressing all feedback
If review takes time:
- Be patient - reviewers are volunteers
- Ping politely if no response after 3-5 days
- Keep your branch up to date with main
After Approval¶
-
Squash commits (if requested):
-
Wait for CI to pass
- Maintainer will merge your PR
Code Review Guidelines¶
For Contributors¶
Before requesting review: - Self-review your changes - Run all checks locally - Ensure PR description is complete - Add screenshots/GIFs for UI changes
During review: - Respond to all comments - Be open to feedback - Ask questions if unclear - Update the PR promptly
For Reviewers¶
What to look for:
- Correctness:
- Does the code do what it claims?
- Are edge cases handled?
-
Is error handling appropriate?
-
Tests:
- Are there tests for new functionality?
- Do tests cover edge cases?
-
Are tests clear and maintainable?
-
Style:
- Does it follow project conventions?
- Is the code readable?
-
Are names descriptive?
-
Documentation:
- Are public APIs documented?
- Is the PR description clear?
-
Are comments helpful (not obvious)?
-
Architecture:
- Does it fit the project structure?
- Are dependencies appropriate?
-
Is it maintainable?
-
Security:
- No hardcoded secrets
- Input validation present
- SQL injection prevented
- RBAC enforced
How to review: - Be constructive and specific - Explain the "why" behind suggestions - Ask questions instead of making demands - Praise good solutions - Use GitHub's "Start a review" feature - Request changes or approve when done
Git Hooks¶
What Are Git Hooks?¶
Git hooks are scripts that run automatically before/after git commands. We use Lefthook to manage hooks.
Installed Hooks¶
Pre-commit (runs before commit):
- Format Go code (goimports, go fmt)
- Lint Go code (golangci-lint --fast)
- Format TypeScript (prettier)
- Lint TypeScript (eslint)
- Format protobuf (buf format)
- Lint protobuf (buf lint)
- Validate commit message format
- Regenerate STATUS.md
Typical run time: < 5 seconds
Managing Hooks¶
# Install hooks
task hooks:install
# Run hooks manually (test before commit)
task hooks:run
# Run all hooks (including optional ones)
task hooks:run-all
# Skip hooks for one commit (not recommended)
git commit --no-verify -m "emergency fix"
# Or
LEFTHOOK=0 git commit -m "skip hooks"
# Uninstall hooks
task hooks:uninstall
Troubleshooting Hooks¶
Hooks are slow: - First run is slower (installs tools) - Subsequent runs should be < 5 seconds - Reduce staged files if possible
Hooks failing:
# Run manually to see full output
lefthook run pre-commit -v
# Check individual tool
golangci-lint run ./...
go fmt ./...
Can't commit: - Fix the errors shown by hooks - Or skip hooks temporarily (not recommended) - Ask for help in GitHub Discussions
Release Process¶
Versioning¶
We use Semantic Versioning:
- MAJOR: Breaking changes (v1.0.0 → v2.0.0)
- MINOR: New features, backward-compatible (v1.0.0 → v1.1.0)
- PATCH: Bug fixes, backward-compatible (v1.0.0 → v1.0.1)
Release Workflow¶
For maintainers only:
-
Update version:
-
Create release commit:
-
Create tag:
-
GitHub Actions will:
- Run tests
- Build binaries
- Create GitHub release
- Publish Docker images
Communication¶
GitHub Issues¶
Use issues for: - Bug reports - Feature requests - Questions about usage - Documentation improvements
Issue templates: - Bug Report: Describe the bug with steps to reproduce - Feature Request: Propose new functionality - Question: Ask about usage or implementation
GitHub Discussions¶
Use discussions for: - General questions - Design proposals - Show and tell - Community conversations
Pull Request Discussions¶
Use PR comments for: - Code review feedback - Implementation questions - Design alternatives - Clarifications
Getting Help¶
Stuck? Here's how to get help:
- Check documentation (see project root):
README.mdDEVELOPMENT.mdTESTING.md-
Search existing issues and discussions
-
Ask in GitHub Discussions
-
Open an issue if you found a bug
When asking for help: - Provide context (what you're trying to do) - Include error messages (full stack traces) - Show what you've tried - Share relevant code snippets - Be patient and polite
Summary¶
Quick contribution checklist:
- Fork and clone repository
- Create feature branch from
main - Make changes with tests
- Run
task cito verify - Commit with conventional message
- Push to your fork
- Create pull request
- Address review feedback
- Wait for approval and merge
Remember: - Quality over speed - Tests are required - Documentation matters - Be respectful and professional - Ask questions when stuck
Thank you for contributing to ocmonica! Your contributions make this project better for everyone.