Thank you for your interest in contributing to BaluHost! This document provides guidelines and instructions for contributing to the project.
We welcome contributions of all kinds:
- 🐛 Bug reports and fixes
- ✨ New features
- 📚 Documentation improvements
- 🧪 Tests
- 🎨 UI/UX enhancements
- 🌍 Translations
- Check existing issues - Someone might already be working on it
- Read the documentation - Familiarize yourself with the architecture
- Ask questions - Open a discussion if you're unsure
- Python 3.11+ (Backend)
- Node.js 18+ (Frontend)
- Git
# 1. Fork and clone the repository
git clone https://github.com/YOUR_USERNAME/BaluHost.git
cd BaluHost
# 2. Start development environment
python start_dev.py
# This will:
# - Set up Python virtual environment
# - Install dependencies
# - Start FastAPI backend (port 8000)
# - Start Vite dev server (port 5173)
# - Initialize 2x5GB RAID1 sandbox storageBackend:
cd backend
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
uvicorn app.main:app --reload --port 8000Frontend:
cd client
npm install
npm run devCode Standards:
- Follow PEP 8 style guide
- Use type hints for all functions
- Write docstrings for public functions (Google style)
- Keep functions focused and under 50 lines when possible
Example:
from typing import List
from app.schemas.files import FileItem
def list_files(path: str, owner_id: int) -> List[FileItem]:
"""
List all files in a directory owned by the user.
Args:
path: The directory path to list
owner_id: The ID of the requesting user
Returns:
List of FileItem objects
Raises:
PermissionError: If user doesn't have access
FileNotFoundError: If path doesn't exist
"""
# Implementation
passStructure:
- Services in
app/services/- Business logic - Routes in
app/api/routes/- API endpoints - Schemas in
app/schemas/- Pydantic models - Use async/await for I/O operations
Linting:
cd backend
black app/ # Format code
pylint app/ # Check code quality
mypy app/ # Type checkingCode Standards:
- Use TypeScript strict mode
- Functional components with hooks
- Tailwind CSS for styling (no inline styles)
- Custom hooks in
src/hooks/
Example:
import { useState, useEffect } from 'react';
import { FileItem } from '../types';
interface FileListProps {
path: string;
onFileClick: (file: FileItem) => void;
}
export default function FileList({ path, onFileClick }: FileListProps) {
const [files, setFiles] = useState<FileItem[]>([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
loadFiles();
}, [path]);
const loadFiles = async () => {
// Implementation
};
return (
<div className="grid gap-4">
{/* Component JSX */}
</div>
);
}Linting:
cd client
npm run lint # ESLint
npm run type-check # TypeScript checkBackend (pytest):
cd backend
python -m pytest # Run all tests
python -m pytest tests/test_*.py # Run specific test
python -m pytest -v --cov=app # With coverageTest Structure:
import pytest
from app.services.files import list_files
def test_list_files_success():
"""Test successful file listing."""
files = list_files("/demo", owner_id=1)
assert len(files) > 0
assert all(f.owner_id == 1 for f in files)
def test_list_files_permission_denied():
"""Test permission denied for unauthorized access."""
with pytest.raises(PermissionError):
list_files("/demo", owner_id=999)Frontend (Vitest):
cd client
npm run test- All new features must have tests
- Don't drop below the CI coverage floor: 65% on
backend/app/, 23% lines onclient/src/(--cov-fail-under/ Vitestthresholds). These are regression guards frozen just under the current measurement, not quality targets — raise them when the numbers climb. - Tests should be deterministic (no random failures)
- Use dev-mode fixtures for reproducibility
Your fork runs the BaluHost CI pipeline out of the box on GitHub-hosted runners — open a PR inside your fork to trigger it. To choose which workflows run, or to run backend tests / deploys on your own hardware, see Self-Hosting & Fork CI/CD.
Important: All contributions go through Pull Requests targeting
main. Branch offmain, then open your PR againstmain. There is no separate integration branch — thedevelopmentbranch was retired on 2026-05-06.
Branch model:
main— Production. Changes land only through PRs. Every merge tomainis tagged as a pre-release and deployed to production via GitHub Actions (self-hosted runner), so keepmainreleasable.feature/*,fix/*,docs/*, etc. — Working branches, created frommainand merged back intomain.
Stable releases are cut separately by the maintainer via the manual release-stable.yml workflow (workflow_dispatch).
feature/description- New featuresfix/description- Bug fixesdocs/description- Documentationrefactor/description- Code refactoringtest/description- Test additions
Examples:
feature/file-sharingfix/upload-progress-bardocs/api-endpoints
Follow Conventional Commits format:
<type>(<scope>): <subject>
<body>
<footer>
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting)refactor: Code refactoringtest: Adding/updating testschore: Maintenance tasks
Examples:
feat(files): add file sharing with public links
Implemented public link generation with optional password
protection and expiry dates. Users can now share files
with external parties without requiring an account.
Closes #123
fix(upload): prevent duplicate file uploads
Added duplicate detection before upload to prevent
overwriting files accidentally.
Fixes #456
-
Create a working branch from
maingit checkout main git pull origin main git checkout -b feature/my-feature
-
Make your changes
- Write clean, documented code
- Add/update tests
- Update documentation
-
Test thoroughly
# Backend cd backend && python -m pytest # Frontend cd client && npm run build
-
Commit your changes
git add . git commit -m "feat(scope): descriptive message"
-
Push to your fork
git push origin feature/my-feature
-
Open a Pull Request against
main- Base branch:
main - Use a clear, descriptive title following Conventional Commits
- Reference related issues (
Closes #123) - Describe what changed and why
- Include screenshots for UI changes
- Wait for CI to pass (
backend-tests,frontend-build). A maintainer reviews and merges — merging tomaincreates a pre-release tag and deploys to production.
- Base branch:
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Documentation update
- [ ] Refactoring
## Related Issues
Closes #123
Related to #456
## Testing
- [ ] Backend tests pass
- [ ] Frontend builds successfully
- [ ] Manual testing completed
## Screenshots (if applicable)- Open an issue or discussion
- Describe the feature and use case
- Get feedback from maintainers
- Create feature branch
- Implement backend (if needed)
- Add service logic
- Add API routes
- Add schemas
- Implement frontend (if needed)
- Create/update components
- Add API calls
- Update UI
- Update
TECHNICAL_DOCUMENTATION.md - Add feature-specific docs in
docs/ - Update API documentation
- Add code comments
- Write unit tests
- Write integration tests
- Manual testing in dev mode
- Test edge cases
- Create pull request
- Address review comments
- Update based on feedback
Python Docstrings:
def complex_function(param1: str, param2: int) -> dict:
"""
Short description of function.
Longer description if needed, explaining behavior,
edge cases, and important details.
Args:
param1: Description of first parameter
param2: Description of second parameter
Returns:
Dictionary containing results with keys:
- 'status': Operation status
- 'data': Result data
Raises:
ValueError: If param2 is negative
PermissionError: If user lacks access
Example:
>>> result = complex_function("test", 42)
>>> print(result['status'])
'success'
"""
passTypeScript Comments:
/**
* Uploads a file to the server with progress tracking.
*
* @param file - The file to upload
* @param path - Target directory path
* @param onProgress - Callback for upload progress (0-100)
* @returns Promise resolving to uploaded file metadata
* @throws {Error} If upload fails or quota exceeded
*
* @example
* ```ts
* await uploadFile(file, "/documents", (progress) => {
* console.log(`Upload: ${progress}%`);
* });
* ```
*/
async function uploadFile(
file: File,
path: string,
onProgress?: (progress: number) => void
): Promise<FileItem> {
// Implementation
}Create a new doc in docs/ for major features:
Template:
# Feature Name
## Overview
Brief description of the feature
## Use Cases
- Use case 1
- Use case 2
## Architecture
How it's implemented (diagrams if helpful)
## API Endpoints
List of relevant endpoints
## Configuration
Environment variables and settings
## Examples
Code examples and usage scenarios
## Testing
How to test this feature
## Future Improvements
Ideas for enhancement- Search existing issues
- Test in dev mode with latest code
- Collect error messages and logs
**Describe the bug**
A clear description of what the bug is.
**To Reproduce**
1. Go to '...'
2. Click on '...'
3. See error
**Expected behavior**
What you expected to happen.
**Screenshots**
If applicable, add screenshots.
**Environment:**
- OS: [e.g. Windows 11, Ubuntu 22.04]
- Python version: [e.g. 3.11.5]
- Node version: [e.g. 18.17.0]
- Browser: [e.g. Chrome 120]
**Additional context**
Any other relevant information.- ❌ Commit sensitive data (passwords, tokens, keys)
- ❌ Submit PRs without tests
- ❌ Use
anytype in TypeScript - ❌ Add dependencies without discussion
- ✅ Write tests for your code
- ✅ Update documentation
- ✅ Follow code style guidelines
- ✅ Keep PRs focused and small
- ✅ Respond to review comments
- TECHNICAL_DOCUMENTATION.md - Complete feature docs
- docs/ - Feature-specific documentation
- TODO.md - Roadmap and planned features
- FastAPI: https://fastapi.tiangolo.com/
- React: https://react.dev/
- TypeScript: https://www.typescriptlang.org/docs/
- Tailwind CSS: https://tailwindcss.com/docs
- Pydantic: https://docs.pydantic.dev/
- Open a Discussion for questions
- Report bugs or request features via GitHub Issues
- Check existing documentation first
DO NOT open public issues for security vulnerabilities. See SECURITY.md for the private reporting process (GitHub Security Advisories preferred).
This project adopts the Contributor Covenant (v2.1). By participating, you agree to uphold it. In short: be respectful, inclusive, and professional — we're all here to learn and build something great together.
- Be welcoming to newcomers
- Respect differing opinions
- Accept constructive criticism
- Focus on what's best for the project
- Show empathy towards others
See CODE_OF_CONDUCT.md for the full text and how to report unacceptable behavior.
Contributors will be recognized in:
- README.md contributors section
- Release notes
- Project documentation
Thank you for contributing to BaluHost! 🚀