docs: comprehensive documentation overhaul

Add complete documentation structure:
- Frontend architecture documentation
- Database schema documentation
- Deployment guides (Docker, Traefik, Authentik, Environment)
- Development guides (Setup, Testing, Contributing, Quality Gates)
- Deployment architecture documentation
- Updated docs README with complete navigation

All new features and APIs are now documented.
Quality gates: docs only, no code changes
This commit is contained in:
Fusion
2026-05-19 14:18:20 +02:00
parent 6807f449b7
commit 83f94b1f09
31 changed files with 5498 additions and 0 deletions
+261
View File
@@ -0,0 +1,261 @@
# Contributing Guide
## Welcome
Thank you for your interest in contributing to Headquarter! This document provides guidelines and workflows for contributing.
## Getting Started
1. Fork the repository
2. Clone your fork: `git clone https://github.com/your-username/headquarter.git`
3. Set up development environment (see [Setup Guide](./setup.md))
4. Create a branch: `git checkout -b feature/your-feature`
## Development Workflow
### 1. Find or Create an Issue
- Check existing issues for something to work on
- Create an issue to discuss new features before implementing
- Comment on issues to claim them
### 2. Create a Branch
```bash
# Feature branch
git checkout -b feature/description
# Bug fix branch
git checkout -b fix/description
# Documentation branch
git checkout -b docs/description
```
### 3. Make Changes
- Write clear, concise code
- Follow existing patterns and conventions
- Add tests for new functionality
- Update documentation as needed
### 4. Run Quality Gates
```bash
# Backend
cd apps/api
ruff check src/ tests/
mypy src/
pytest
# Frontend
cd apps/web
npm run lint
npm run typecheck
npm run test
npm run build
```
### 5. Commit Changes
We use conventional commits:
```bash
# Format: type(scope): description
# Examples:
git commit -m "feat(auth): add OAuth2 login"
git commit -m "fix(api): handle missing user gracefully"
git commit -m "docs(readme): update installation instructions"
git commit -m "test(git): add URL parsing tests"
git commit -m "refactor(models): extract base repository"
```
**Types**:
- `feat`: New feature
- `fix`: Bug fix
- `docs`: Documentation
- `style`: Formatting (no code change)
- `refactor`: Code restructuring
- `test`: Adding tests
- `chore`: Maintenance tasks
### 6. Push and Create Pull Request
```bash
git push origin feature/description
```
**PR Description should include**:
- What changed and why
- How to test
- Screenshots (for UI changes)
- Link to related issue
## Code Standards
### Python (Backend)
**Style**: Follow PEP 8 and project conventions
```python
# Function naming: snake_case
def get_user_by_id(user_id: str) -> User | None:
pass
# Class naming: PascalCase
class GitRepositoryService:
pass
# Constants: UPPER_SNAKE_CASE
MAX_FILE_SIZE = 1024 * 1024 # 1MB
# Type hints required
def process_data(data: dict[str, Any]) -> ProcessedResult:
pass
```
**Docstrings**: Google style
```python
def extract_base_repo_url(url: str) -> str | None:
"""Extract base repository URL from a browser URL.
Args:
url: The URL to parse, may be a browser URL or git URL.
Returns:
The base repository URL with .git suffix, or None if parsing fails.
Examples:
>>> extract_base_repo_url("https://github.com/user/repo/tree/main")
'https://github.com/user/repo.git'
>>> extract_base_repo_url("https://github.com/user/repo.git")
'https://github.com/user/repo.git'
"""
pass
```
### TypeScript (Frontend)
**Style**: Follow existing patterns
```typescript
// Interface naming: PascalCase
interface User {
id: string;
email: string;
name: string;
}
// Function naming: camelCase
function getUserById(userId: string): Promise<User> {
return api.get(`/users/${userId}`);
}
// Component naming: PascalCase
const UserProfile: React.FC<UserProfileProps> = ({ user }) => {
return <div>{user.name}</div>;
};
```
## Testing Requirements
### New Features
- Unit tests for business logic
- Integration tests for API endpoints
- Component tests for UI components
### Bug Fixes
- Regression test that would catch the bug
- Verify fix with the test
### Example
```python
# Backend test
def test_extract_github_browser_url():
url = "https://github.com/user/repo/tree/main"
result = extract_base_repo_url(url)
assert result == "https://github.com/user/repo.git"
# Frontend test
test('shows file tree', () => {
render(<FileTree files={mockFiles} onFileClick={() => {}} />);
expect(screen.getByText('src')).toBeInTheDocument();
});
```
## Documentation
Update documentation when:
- Adding new features
- Changing API endpoints
- Modifying configuration
- Adding environment variables
**Documentation locations**:
- `README.md` - Project overview
- `docs/features/` - Feature documentation
- `docs/api/` - API documentation
- `docs/deployment/` - Deployment guides
## Review Process
1. **Automated checks** must pass (CI/CD)
2. **Code review** by at least one maintainer
3. **Approval** required before merge
4. **Squash merge** to keep history clean
### Review Checklist
**For Authors**:
- [ ] Tests pass locally
- [ ] Quality gates pass
- [ ] Documentation updated
- [ ] PR description is clear
**For Reviewers**:
- [ ] Code makes sense
- [ ] Tests cover changes
- [ ] No security issues
- [ ] Follows conventions
## Release Process
1. Update version in `pyproject.toml` and `package.json`
2. Update `CHANGELOG.md`
3. Create git tag: `git tag v1.2.3`
4. Push tag: `git push origin v1.2.3`
5. Create GitHub release with notes
## Community
### Communication Channels
- GitHub Issues: Bug reports and feature requests
- GitHub Discussions: Questions and ideas
- Pull Requests: Code contributions
### Code of Conduct
- Be respectful and inclusive
- Welcome newcomers
- Focus on constructive feedback
- Respect different viewpoints
## Questions?
- Check existing documentation
- Search closed issues
- Ask in GitHub Discussions
- Join community chat (if available)
## Resources
- [Development Setup](./setup.md)
- [Testing Guide](./testing.md)
- [Quality Gates](./quality-gates.md)
- [Project README](../../README.md)
+365
View File
@@ -0,0 +1,365 @@
# Quality Gates
## Overview
All code changes must pass quality gates before being merged. These gates ensure code consistency, type safety, and prevent common issues.
## Backend Quality Gates
### 1. Code Formatting (ruff)
**Purpose**: Enforce consistent code style
```bash
cd apps/api
ruff check src/ tests/
ruff format src/ tests/
```
**Configuration** (`pyproject.toml`):
```toml
[tool.ruff]
line-length = 100
target-version = "py311"
select = ["E", "F", "I", "W", "UP"]
ignore = ["E501"]
[tool.ruff.lint.pydocstyle]
convention = "google"
```
**Pre-commit hook**:
```bash
# Install pre-commit
pip install pre-commit
pre-commit install
# Run manually
pre-commit run --all-files
```
### 2. Type Checking (mypy)
**Purpose**: Catch type errors before runtime
```bash
cd apps/api
mypy src/
```
**Configuration** (`pyproject.toml`):
```toml
[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_ignores = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
```
**Common issues**:
- Missing type hints on function parameters
- Returning wrong type
- None checks needed
### 3. Unit Tests (pytest)
**Purpose**: Verify functionality works as expected
```bash
cd apps/api
pytest -v
```
**Requirements**:
- All tests must pass
- New code should have tests
- Coverage should not decrease
### 4. Security Checks
**Bandit** (security linter):
```bash
bandit -r src/
```
**Safety** (dependency vulnerabilities):
```bash
safety check
```
## Frontend Quality Gates
### 1. Type Checking (TypeScript)
**Purpose**: Catch type errors at build time
```bash
cd apps/web
npm run typecheck
```
**Configuration** (`tsconfig.json`):
```json
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
}
}
```
### 2. Linting (ESLint)
**Purpose**: Enforce code style and catch issues
```bash
cd apps/web
npm run lint
npm run lint:fix
```
**Configuration** (`.eslintrc.cjs`):
```javascript
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}
```
### 3. Build Check
**Purpose**: Ensure production build succeeds
```bash
cd apps/web
npm run build
```
**Requirements**:
- No TypeScript errors
- No build warnings
- Bundle size reasonable
### 4. Unit Tests (Vitest)
```bash
cd apps/web
npm run test
```
**Requirements**:
- All tests pass
- No test failures
- Coverage maintained
## Running All Gates
### Backend
```bash
cd apps/api
# Run all gates
ruff check src/ tests/ && \
mypy src/ && \
pytest
# Or use Makefile
make lint # ruff + mypy
make test # pytest
make check # All backend gates
```
### Frontend
```bash
cd apps/web
# Run all gates
npm run lint && \
npm run typecheck && \
npm run test && \
npm run build
# Or use package.json scripts
npm run check # All frontend gates
```
### Full Project
```bash
# From root
make check-all # Run all backend and frontend gates
```
## Continuous Integration
All quality gates run automatically on:
- Every Pull Request
- Every push to main branch
**CI Pipeline**:
```yaml
stages:
- lint
- test
- build
backend-lint:
stage: lint
script:
- cd apps/api && ruff check src/ tests/
- cd apps/api && mypy src/
backend-test:
stage: test
script:
- cd apps/api && pytest -v
frontend-lint:
stage: lint
script:
- cd apps/web && npm run lint
- cd apps/web && npm run typecheck
frontend-test:
stage: test
script:
- cd apps/web && npm run test
frontend-build:
stage: build
script:
- cd apps/web && npm run build
```
## Fixing Common Issues
### Backend
**ruff: Line too long**
```python
# Bad
result = some_very_long_function_name(with_many_parameters, that_make_the_line_too_long)
# Good
result = some_very_long_function_name(
with_many_parameters,
that_make_the_line_too_long,
)
```
**mypy: Missing return type**
```python
# Bad
def get_user(user_id):
return User.query.get(user_id)
# Good
def get_user(user_id: str) -> User | None:
return User.query.get(user_id)
```
### Frontend
**TypeScript: Implicit any**
```typescript
// Bad
function processData(data) {
return data.map(item => item.name);
}
// Good
function processData(data: DataItem[]) {
return data.map(item => item.name);
}
```
**ESLint: Unused variable**
```typescript
// Bad
const [count, setCount] = useState(0);
// count is never used
// Good
const [count] = useState(0);
// Or remove if not needed
```
## IDE Integration
### VS Code
**Settings** (`.vscode/settings.json`):
```json
{
"python.linting.enabled": true,
"python.linting.mypyEnabled": true,
"python.formatting.provider": "ruff",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}
```
### PyCharm
1. **File****Settings****Tools****External Tools**
2. Add ruff and mypy as external tools
3. Set up pre-commit hooks
## Pre-commit Hooks
`.pre-commit-config.yaml`:
```yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.0
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.7.0
hooks:
- id: mypy
additional_dependencies: [types-all]
- repo: local
hooks:
- id: frontend-lint
name: Frontend Lint
entry: bash -c 'cd apps/web && npm run lint'
language: system
files: ^apps/web/
```
## Resources
- [ruff Documentation](https://docs.astral.sh/ruff/)
- [mypy Documentation](https://mypy.readthedocs.io/)
- [ESLint Documentation](https://eslint.org/)
- [TypeScript Handbook](https://www.typescriptlang.org/docs/)
+299
View File
@@ -0,0 +1,299 @@
# Development Setup Guide
## Prerequisites
- Python 3.11+
- Node.js 18+
- PostgreSQL 15+
- Redis 7+
- Git
## Quick Setup
### 1. Clone Repository
```bash
git clone https://github.com/your-org/headquarter.git
cd headquarter
```
### 2. Backend Setup
```bash
cd apps/api
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # Linux/Mac
# .venv\Scripts\activate # Windows
# Install dependencies
pip install -e ".[dev]"
# Copy environment file
cp .env.example .env
# Edit .env with your settings
```
### 3. Frontend Setup
```bash
cd apps/web
# Install dependencies
npm install
# Copy environment file
cp .env.example .env
# Edit .env with your settings
```
### 4. Database Setup
```bash
# Start PostgreSQL and Redis
# (Using Docker or local installation)
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=headquarter postgres:15
docker run -d -p 6379:6379 redis:7
# Create database
createdb headquarter
# Run migrations
cd apps/api
alembic upgrade head
# (Optional) Seed data
python -m src.scripts.seed
```
### 5. Start Development Servers
Terminal 1 - Backend:
```bash
cd apps/api
source .venv/bin/activate
python -m uvicorn src.main:app --reload --port 8000
```
Terminal 2 - Frontend:
```bash
cd apps/web
npm run dev
```
Terminal 3 - (Optional) Authentik:
```bash
# If using local Authentik
docker compose -f docker-compose.authentik.yml up -d
```
## Development Environment Variables
Create `apps/api/.env`:
```bash
APP_ENV=development
DATABASE_URL=postgresql+asyncpg://headquarter:headquarter@localhost:5432/headquarter
REDIS_URL=redis://localhost:6379/0
SESSION_SECRET=dev-session-secret-change-me
API_DOMAIN=localhost
WEB_DOMAIN=localhost
# Authentik (optional for local dev)
AUTHENTIK_DOMAIN=authentik.local
AUTHENTIK_CLIENT_ID=headquarter-web
AUTHENTIK_CLIENT_SECRET=change-me
AUTHENTIK_APPLICATION_SLUG=headquarter-web
```
Create `apps/web/.env`:
```bash
VITE_API_BASE_URL=http://localhost:8000
```
## IDE Setup
### VS Code Extensions
Recommended extensions:
- Python (ms-python.python)
- Pylance (ms-python.vscode-pylance)
- ESLint (dbaeumer.vscode-eslint)
- Prettier (esbenp.prettier-vscode)
- TypeScript Importer (pmneo.tsimporter)
### PyCharm/IntelliJ
1. Open `apps/api` as project
2. Set Python interpreter to `.venv`
3. Enable Django/Flask support for FastAPI
## Debugging
### Backend Debugging
**VS Code launch.json**:
```json
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: FastAPI",
"type": "python",
"request": "launch",
"module": "uvicorn",
"args": ["src.main:app", "--reload", "--port", "8000"],
"jinja": true,
"justMyCode": true
}
]
}
```
**PyCharm**:
1. Run → Edit Configurations
2. Add Python configuration
3. Module name: `uvicorn`
4. Parameters: `src.main:app --reload --port 8000`
### Frontend Debugging
**VS Code launch.json**:
```json
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:5173",
"webRoot": "${workspaceFolder}/apps/web/src"
}
```
## Common Tasks
### Database Migrations
```bash
cd apps/api
# Create new migration
alembic revision --autogenerate -m "description"
# Run migrations
alembic upgrade head
# Downgrade
alembic downgrade -1
# Current version
alembic current
# History
alembic history
```
### Adding Dependencies
**Backend**:
```bash
cd apps/api
# Add production dependency
pip install package-name
# Add to pyproject.toml [project.dependencies]
# Add dev dependency
pip install -e ".[dev]"
# Add to pyproject.toml [project.optional-dependencies.dev]
```
**Frontend**:
```bash
cd apps/web
npm install package-name
npm install -D package-name # dev dependency
```
### Git Workflow
1. Create feature branch: `git checkout -b feature/name`
2. Make changes
3. Run quality gates (see below)
4. Commit: `git commit -m "feat: description"`
5. Push: `git push origin feature/name`
6. Create Pull Request
## Project Structure
```
headquarter/
├── apps/
│ ├── api/ # Backend (FastAPI)
│ │ ├── src/
│ │ │ ├── api/ # API routes
│ │ │ ├── auth/ # Authentication
│ │ │ ├── models/ # Database models
│ │ │ ├── utils/ # Utilities
│ │ │ └── main.py # Entry point
│ │ ├── tests/ # Test suites
│ │ ├── alembic/ # Migrations
│ │ └── pyproject.toml # Dependencies
│ └── web/ # Frontend (React)
│ ├── src/
│ │ ├── api/ # API clients
│ │ ├── components/ # React components
│ │ ├── pages/ # Page components
│ │ └── styles/ # CSS
│ └── package.json # Dependencies
├── docs/ # Documentation
├── docker-compose.yml # Dev setup
└── Makefile # Common commands
```
## Troubleshooting
### Database Connection Errors
```bash
# Check PostgreSQL is running
pg_isready -h localhost -p 5432
# Check credentials
psql postgresql://headquarter:headquarter@localhost:5432/headquarter -c "SELECT 1"
```
### Port Conflicts
```bash
# Find process using port 8000
lsof -i :8000
# Kill process
kill -9 <PID>
```
### Node Modules Issues
```bash
cd apps/web
rm -rf node_modules package-lock.json
npm install
```
### Python Environment Issues
```bash
cd apps/api
rm -rf .venv
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
```
## Resources
- [FastAPI Documentation](https://fastapi.tiangolo.com/)
- [React Documentation](https://react.dev/)
- [SQLAlchemy Documentation](https://docs.sqlalchemy.org/)
- [Alembic Documentation](https://alembic.sqlalchemy.org/)
+365
View File
@@ -0,0 +1,365 @@
# Testing Guide
## Overview
Headquarter has comprehensive testing for both backend and frontend to ensure reliability and catch regressions.
## Backend Testing
### Test Framework
- **pytest**: Test runner
- **pytest-asyncio**: Async test support
- **httpx**: HTTP client for API tests
- **factory-boy**: Test data generation (recommended)
### Test Structure
```
apps/api/tests/
├── conftest.py # Shared fixtures
├── test_auth_api.py # Auth endpoint tests
├── test_auth_services.py # Auth service tests
├── test_models.py # Database model tests
├── test_projects_api.py # Project endpoint tests
├── test_git_repositories.py # Repository tests
└── ...
```
### Running Tests
```bash
cd apps/api
# Run all tests
pytest
# Run with coverage
pytest --cov=src --cov-report=html
# Run specific test file
pytest tests/test_auth_api.py
# Run specific test
pytest tests/test_auth_api.py::test_login_redirect
# Run with verbose output
pytest -v
# Run async tests
pytest --asyncio-mode=auto
```
### Writing Tests
**Unit Test Example**:
```python
import pytest
from src.utils.git_url_parser import extract_base_repo_url
def test_extract_github_url():
url = "https://github.com/user/repo/tree/main"
result = extract_base_repo_url(url)
assert result == "https://github.com/user/repo.git"
def test_valid_git_url_unchanged():
url = "https://github.com/user/repo.git"
result = extract_base_repo_url(url)
assert result == url
```
**Async Test Example**:
```python
import pytest
from httpx import AsyncClient
@pytest.mark.asyncio
async def test_get_projects(client: AsyncClient):
response = await client.get("/projects")
assert response.status_code == 200
assert isinstance(response.json(), list)
```
**API Integration Test**:
```python
@pytest.mark.asyncio
async def test_create_project(client: AsyncClient, auth_headers):
response = await client.post(
"/projects",
json={"name": "Test Project"},
headers=auth_headers
)
assert response.status_code == 201
data = response.json()
assert data["name"] == "Test Project"
assert "id" in data
```
### Test Fixtures
**conftest.py** provides:
```python
import pytest
from httpx import AsyncClient
@pytest.fixture
async def client():
from src.main import app
async with AsyncClient(app=app, base_url="http://test") as client:
yield client
@pytest.fixture
async def auth_headers(client):
# Login and return auth headers
response = await client.post("/auth/login")
# ... setup session
return {"Cookie": "session=..."}
```
### Test Database
Tests use a separate database:
```bash
# Test database URL (from .env)
TEST_DATABASE_URL=postgresql+asyncpg://headquarter:headquarter@localhost:5432/headquarter_test
# Run tests with test DB
TEST_DATABASE_URL=... pytest
```
## Frontend Testing
### Test Framework
- **Vitest**: Test runner
- **React Testing Library**: Component testing
- **jsdom**: DOM environment
### Test Structure
```
apps/web/src/
├── components/
│ └── protected-route.test.tsx
├── pages/
│ ├── dashboard.test.tsx
│ └── projects.test.tsx
└── test/
└── setup.ts # Test setup
```
### Running Tests
```bash
cd apps/web
# Run all tests
npm run test
# Run in watch mode
npm run test -- --watch
# Run with coverage
npm run test -- --coverage
# Run specific file
npm run test -- protected-route
```
### Writing Tests
**Component Test Example**:
```typescript
import { render, screen, fireEvent } from '@testing-library/react';
import { FileTree } from '../components/file-tree';
describe('FileTree', () => {
const mockFiles = [
{ name: 'src', type: 'directory', path: 'src' },
{ name: 'main.py', type: 'file', path: 'src/main.py' },
];
it('renders file list', () => {
render(<FileTree files={mockFiles} onFileClick={() => {}} />);
expect(screen.getByText('src')).toBeInTheDocument();
expect(screen.getByText('main.py')).toBeInTheDocument();
});
it('calls onFileClick when file clicked', () => {
const handleClick = vi.fn();
render(<FileTree files={mockFiles} onFileClick={handleClick} />);
fireEvent.click(screen.getByText('main.py'));
expect(handleClick).toHaveBeenCalledWith(mockFiles[1]);
});
});
```
**Async Test Example**:
```typescript
import { render, screen, waitFor } from '@testing-library/react';
import { ProjectsPage } from '../pages/projects';
describe('ProjectsPage', () => {
it('loads and displays projects', async () => {
render(<ProjectsPage />);
await waitFor(() => {
expect(screen.getByText('My Projects')).toBeInTheDocument();
});
});
});
```
## E2E Testing (Future)
### Playwright Setup
```bash
cd apps/web
npm install -D @playwright/test
npx playwright install
```
**Example E2E Test**:
```typescript
import { test, expect } from '@playwright/test';
test('user can login', async ({ page }) => {
await page.goto('http://localhost:5173');
await page.click('text=Login');
// Authentik login
await page.fill('[name="username"]', 'test@example.com');
await page.fill('[name="password"]', 'password');
await page.click('text=Sign In');
// Should redirect back to app
await expect(page).toHaveURL('http://localhost:5173/dashboard');
});
```
## Test Data
### Factories (Recommended)
Use factory-boy for test data:
```python
# tests/factories.py
import factory
from src.models.user import User
class UserFactory(factory.Factory):
class Meta:
model = User
email = factory.Faker('email')
name = factory.Faker('name')
authentik_id = factory.Faker('uuid4')
```
### Fixtures
```python
@pytest.fixture
async def test_user(db_session):
user = UserFactory()
db_session.add(user)
await db_session.commit()
return user
```
## Coverage Goals
| Component | Target Coverage |
|-----------|----------------|
| Backend API | 80%+ |
| Backend Services | 90%+ |
| Backend Models | 90%+ |
| Frontend Components | 70%+ |
| Frontend Pages | 60%+ |
## Continuous Integration
### GitHub Actions (Example)
```yaml
name: Tests
on: [push, pull_request]
jobs:
backend:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: headquarter
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- run: pip install -e ".[dev]"
- run: pytest --cov=src --cov-report=xml
frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: cd apps/web && npm ci
- run: cd apps/web && npm run test
```
## Best Practices
### Backend
1. **Test isolation**: Each test should be independent
2. **Use fixtures**: Don't repeat setup code
3. **Mock external services**: Authentik, git operations
4. **Test edge cases**: Empty lists, invalid inputs, errors
5. **Async properly**: Use `pytest.mark.asyncio` and async fixtures
### Frontend
1. **Test behavior, not implementation**: Check what user sees
2. **Use data-testid**: For stable selectors
3. **Mock API calls**: Don't hit real backend
4. **Test accessibility**: Use `screen.getByRole`
5. **Snapshot sparingly**: Only for complex UIs
## Debugging Tests
### Backend
```bash
# Run with debugger
pytest --pdb
# Run specific test with verbose
pytest -v -s test_file.py::test_name
# Show print statements
pytest -s
```
### Frontend
```bash
# Debug mode
npm run test -- --reporter=verbose
# Show browser (for E2E)
npx playwright test --headed
```
## Resources
- [pytest Documentation](https://docs.pytest.org/)
- [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/)
- [Vitest Documentation](https://vitest.dev/)
- [Playwright Documentation](https://playwright.dev/)