diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..3ab3f49 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,387 @@ +# Contributing to FastAPI + Next.js Template + +First off, thank you for considering contributing to this project! ๐ŸŽ‰ + +This template aims to be a rock-solid foundation for full-stack applications, and your contributions help make that possible. + +## Table of Contents + +- [Code of Conduct](#code-of-conduct) +- [How Can I Contribute?](#how-can-i-contribute) +- [Development Setup](#development-setup) +- [Coding Standards](#coding-standards) +- [Testing Guidelines](#testing-guidelines) +- [Commit Messages](#commit-messages) +- [Pull Request Process](#pull-request-process) + +--- + +## Code of Conduct + +This project is committed to providing a welcoming and inclusive environment. We expect all contributors to: + +- Be respectful and considerate +- Welcome newcomers and help them learn +- Focus on constructive criticism +- Accept feedback gracefully +- Prioritize the community's well-being + +Unacceptable behavior includes harassment, trolling, insulting comments, and personal attacks. + +--- + +## How Can I Contribute? + +### Reporting Bugs + +Found a bug? Help us fix it! + +1. **Check existing issues** to avoid duplicates +2. **Create a new issue** with: + - Clear, descriptive title + - Steps to reproduce + - Expected vs. actual behavior + - Environment details (OS, Python/Node version, etc.) + - Screenshots/logs if applicable + +### Suggesting Features + +Have an idea for improvement? + +1. **Check existing issues/discussions** first +2. **Open a discussion** to gauge interest +3. **Explain the use case** and benefits +4. **Consider implementation complexity** + +Remember: This is a *template*, not a full application. Features should be: +- Broadly useful +- Well-documented +- Thoroughly tested +- Maintainable long-term + +### Improving Documentation + +Documentation improvements are always welcome! + +- Fix typos or unclear explanations +- Add examples or diagrams +- Expand on complex topics +- Update outdated information +- Translate documentation (future) + +### Contributing Code + +Ready to write some code? Awesome! + +1. **Pick an issue** (or create one) +2. **Comment** that you're working on it +3. **Fork and branch** from `main` +4. **Write code** following our standards +5. **Add tests** (required for features) +6. **Update docs** if needed +7. **Submit a PR** with clear description + +--- + +## Development Setup + +### Backend Development + +```bash +cd backend + +# Setup virtual environment +python -m venv .venv +source .venv/bin/activate + +# Install dependencies +pip install -r requirements.txt + +# Setup environment +cp .env.example .env +# Edit .env with your settings + +# Run migrations +alembic upgrade head + +# Run tests +IS_TEST=True pytest + +# Start dev server +uvicorn app.main:app --reload +``` + +### Frontend Development + +```bash +cd frontend + +# Install dependencies +npm install + +# Setup environment +cp .env.local.example .env.local + +# Generate API client +npm run generate:api + +# Run tests +npm test +npm run test:e2e:ui + +# Start dev server +npm run dev +``` + +--- + +## Coding Standards + +### Backend (Python) + +- **Style**: Follow PEP 8 +- **Type hints**: Use type annotations +- **Async**: Use async/await for I/O operations +- **Documentation**: Docstrings for all public functions/classes +- **Error handling**: Use custom exceptions appropriately +- **Security**: Never trust user input, validate everything + +Example: +```python +async def get_user_by_email( + db: AsyncSession, + *, + email: str +) -> Optional[User]: + """ + Get user by email address. + + Args: + db: Database session + email: User's email address + + Returns: + User if found, None otherwise + """ + result = await db.execute( + select(User).where(User.email == email) + ) + return result.scalar_one_or_none() +``` + +### Frontend (TypeScript/React) + +- **Style**: Use Prettier (configured) +- **TypeScript**: Strict mode, no `any` types +- **Components**: Functional components with hooks +- **Naming**: PascalCase for components, camelCase for functions +- **Imports**: Use absolute imports with `@/` alias +- **Dependencies**: Use provided auth context (never import stores directly) + +Example: +```typescript +interface UserProfileProps { + userId: string; +} + +export function UserProfile({ userId }: UserProfileProps) { + const { user } = useAuth(); + const { data, isLoading } = useQuery({ + queryKey: ['user', userId], + queryFn: () => fetchUser(userId), + }); + + if (isLoading) return ; + + return
...
; +} +``` + +### Key Patterns + +- **Backend**: Use CRUD pattern, keep routes thin, business logic in services +- **Frontend**: Use React Query for server state, Zustand for client state +- **Both**: Handle errors gracefully, log appropriately, write tests + +--- + +## Testing Guidelines + +### Backend Tests + +- **Coverage target**: >90% for new code +- **Test types**: Unit, integration, and security tests +- **Fixtures**: Use pytest fixtures from `conftest.py` +- **Database**: Use `async_test_db` fixture for isolation +- **Assertions**: Be specific about what you're testing + +```python +@pytest.mark.asyncio +async def test_create_user(client, async_test_superuser, superuser_token): + """Test creating a new user.""" + response = await client.post( + "/api/v1/admin/users", + headers={"Authorization": f"Bearer {superuser_token}"}, + json={ + "email": "newuser@example.com", + "password": "SecurePass123!", + "first_name": "New", + "last_name": "User" + } + ) + + assert response.status_code == 201 + data = response.json() + assert data["email"] == "newuser@example.com" + assert "password" not in data # Never expose passwords +``` + +### Frontend E2E Tests + +- **Use Playwright**: For end-to-end user flows +- **Be specific**: Use accessible selectors (roles, labels) +- **Be reliable**: Avoid flaky tests with proper waits +- **Be fast**: Group related tests, use parallel execution + +```typescript +test('user can login and view profile', async ({ page }) => { + // Login + await page.goto('/auth/login'); + await page.fill('#email', 'user@example.com'); + await page.fill('#password', 'password123'); + await page.click('button[type="submit"]'); + + // Should redirect to dashboard + await expect(page).toHaveURL(/\/dashboard/); + + // Should see user name + await expect(page.getByText('Welcome, John')).toBeVisible(); +}); +``` + +### Unit Tests (Frontend) + +- **Test behavior**: Not implementation details +- **Mock dependencies**: Use Jest mocks appropriately +- **Test accessibility**: Include a11y checks when relevant + +--- + +## Commit Messages + +Write clear, descriptive commit messages: + +### Format + +``` +: + + + +