diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 8cb144f..f3a9ca0 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -16,7 +16,8 @@ "Bash(python:*)", "Bash(python -m pytest:*)", "Bash(python3 -m pytest:*)", - "WebFetch(domain:docs.anthropic.com)" + "WebFetch(domain:docs.anthropic.com)", + "WebFetch(domain:github.com)" ], "deny": [] } diff --git a/claude-code-full-guide/.claude/commands/execute-parallel.md b/claude-code-full-guide/.claude/commands/execute-parallel.md new file mode 100644 index 0000000..4d522b6 --- /dev/null +++ b/claude-code-full-guide/.claude/commands/execute-parallel.md @@ -0,0 +1,27 @@ +# Parallel Task Version Execution + +## Variables +FEATURE_NAME: $ARGUMENTS +PLAN_TO_EXECUTE: $ARGUMENTS +NUMBER_OF_PARALLEL_WORKTREES: $ARGUMENTS + +## Instructions + +We're going to create NUMBER_OF_PARALLEL_WORKTREES new subagents that use the Task tool to create N versions of the same feature in parallel. + +Be sure to read PLAN_TO_EXECUTE. + +This enables use to concurrently build the same feature in parallel so we can test and validate each subagent's changes in isolation then pick the best changes. + +The first agent will run in trees/-1/ +The second agent will run in trees/-2/ +... +The last agent will run in trees/-/ + +The code in trees/-/ will be identical to the code in the current branch. It will be setup and ready for you to build the feature end to end. + +Each agent will independently implement the engineering plan detailed in PLAN_TO_EXECUTE in their respective workspace. + +When the subagent completes it's work, have the subagent to report their final changes made in a comprehensive `RESULTS.md` file at the root of their respective workspace. + +Make sure agents don't run any tests or other code - focus on the code changes only. \ No newline at end of file diff --git a/claude-code-full-guide/.claude/commands/execute-prp.md b/claude-code-full-guide/.claude/commands/execute-prp.md new file mode 100644 index 0000000..81fb8ea --- /dev/null +++ b/claude-code-full-guide/.claude/commands/execute-prp.md @@ -0,0 +1,40 @@ +# Execute BASE PRP + +Implement a feature using using the PRP file. + +## PRP File: $ARGUMENTS + +## Execution Process + +1. **Load PRP** + - Read the specified PRP file + - Understand all context and requirements + - Follow all instructions in the PRP and extend the research if needed + - Ensure you have all needed context to implement the PRP fully + - Do more web searches and codebase exploration as needed + +2. **ULTRATHINK** + - Think hard before you execute the plan. Create a comprehensive plan addressing all requirements. + - Break down complex tasks into smaller, manageable steps using your todos tools. + - Use the TodoWrite tool to create and track your implementation plan. + - Identify implementation patterns from existing code to follow. + +3. **Execute the plan** + - Execute the PRP + - Implement all the code + +4. **Validate** + - Run each validation command + - Fix any failures + - Re-run until all pass + +5. **Complete** + - Ensure all checklist items done + - Run final validation suite + - Report completion status + - Read the PRP again to ensure you have implemented everything + +6. **Reference the PRP** + - You can always reference the PRP again if needed + +Note: If validation fails, use error patterns in PRP to fix and retry. \ No newline at end of file diff --git a/claude-code-full-guide/.claude/commands/fix-github-issue.md b/claude-code-full-guide/.claude/commands/fix-github-issue.md new file mode 100644 index 0000000..3db87dc --- /dev/null +++ b/claude-code-full-guide/.claude/commands/fix-github-issue.md @@ -0,0 +1,14 @@ +Please analyze and fix the GitHub issue: $ARGUMENTS. + +Follow these steps: + +1. Use `gh issue view` to get the issue details +2. Understand the problem described in the issue +3. Search the codebase for relevant files +4. Implement the necessary changes to fix the issue +5. Write and run tests to verify the fix +6. Ensure code passes linting and type checking +7. Create a descriptive commit message +8. Push and create a PR + +Remember to use the GitHub CLI (`gh`) for all GitHub-related tasks. \ No newline at end of file diff --git a/claude-code-full-guide/.claude/commands/generate-prp.md b/claude-code-full-guide/.claude/commands/generate-prp.md new file mode 100644 index 0000000..e1b4ac8 --- /dev/null +++ b/claude-code-full-guide/.claude/commands/generate-prp.md @@ -0,0 +1,69 @@ +# Create PRP + +## Feature file: $ARGUMENTS + +Generate a complete PRP for general feature implementation with thorough research. Ensure context is passed to the AI agent to enable self-validation and iterative refinement. Read the feature file first to understand what needs to be created, how the examples provided help, and any other considerations. + +The AI agent only gets the context you are appending to the PRP and training data. Assuma the AI agent has access to the codebase and the same knowledge cutoff as you, so its important that your research findings are included or referenced in the PRP. The Agent has Websearch capabilities, so pass urls to documentation and examples. + +## Research Process + +1. **Codebase Analysis** + - Search for similar features/patterns in the codebase + - Identify files to reference in PRP + - Note existing conventions to follow + - Check test patterns for validation approach + +2. **External Research** + - Search for similar features/patterns online + - Library documentation (include specific URLs) + - Implementation examples (GitHub/StackOverflow/blogs) + - Best practices and common pitfalls + +3. **User Clarification** (if needed) + - Specific patterns to mirror and where to find them? + - Integration requirements and where to find them? + +## PRP Generation + +Using PRPs/templates/prp_base.md as template: + +### Critical Context to Include and pass to the AI agent as part of the PRP +- **Documentation**: URLs with specific sections +- **Code Examples**: Real snippets from codebase +- **Gotchas**: Library quirks, version issues +- **Patterns**: Existing approaches to follow + +### Implementation Blueprint +- Start with pseudocode showing approach +- Reference real files for patterns +- Include error handling strategy +- list tasks to be completed to fullfill the PRP in the order they should be completed + +### Validation Gates (Must be Executable) eg for python +```bash +# Syntax/Style +ruff check --fix && mypy . + +# Unit Tests +uv run pytest tests/ -v + +``` + +*** CRITICAL AFTER YOU ARE DONE RESEARCHING AND EXPLORING THE CODEBASE BEFORE YOU START WRITING THE PRP *** + +*** ULTRATHINK ABOUT THE PRP AND PLAN YOUR APPROACH THEN START WRITING THE PRP *** + +## Output +Save as: `PRPs/{feature-name}.md` + +## Quality Checklist +- [ ] All necessary context included +- [ ] Validation gates are executable by AI +- [ ] References existing patterns +- [ ] Clear implementation path +- [ ] Error handling documented + +Score the PRP on a scale of 1-10 (confidence level to succeed in one-pass implementation using claude codes) + +Remember: The goal is one-pass implementation success through comprehensive context. \ No newline at end of file diff --git a/claude-code-full-guide/.claude/commands/prep-parallel.md b/claude-code-full-guide/.claude/commands/prep-parallel.md new file mode 100644 index 0000000..25004ed --- /dev/null +++ b/claude-code-full-guide/.claude/commands/prep-parallel.md @@ -0,0 +1,14 @@ +# Initialize parallel git worktree directories for parallel Claude Code agents + +## Variables +FEATURE_NAME: $ARGUMENTS +NUMBER_OF_PARALLEL_WORKTREES: $ARGUMENTS + +## Execute these commands +> Execute the loop in parallel with the Batch and Task tool + +- create a new dir `trees/` +- for i in NUMBER_OF_PARALLEL_WORKTREES + - RUN `git worktree add -b FEATURE_NAME-i ./trees/FEATURE_NAME-i` + - RUN `cd trees/FEATURE_NAME-i`, `git ls-files` to validate +- RUN `git worktree list` to verify all trees were created properly \ No newline at end of file diff --git a/claude-code-full-guide/.claude/settings.local.json b/claude-code-full-guide/.claude/settings.local.json new file mode 100644 index 0000000..1c6fc77 --- /dev/null +++ b/claude-code-full-guide/.claude/settings.local.json @@ -0,0 +1,27 @@ +{ + "permissions": { + "allow": [ + "Bash(grep:*)", + "Bash(ls:*)", + "Bash(source:*)", + "Bash(find:*)", + "Bash(mv:*)", + "Bash(mkdir:*)", + "Bash(tree:*)", + "Bash(ruff:*)", + "Bash(touch:*)", + "Bash(cat:*)", + "Bash(ruff check:*)", + "Bash(pytest:*)", + "Bash(python:*)", + "Bash(python -m pytest:*)", + "Bash(python3 -m pytest:*)", + "WebFetch(domain:*)", + "Bash(gh issue view:*)", + "mcp__puppeteer__puppeteer_navigate", + "mcp__puppeteer__puppeteer_screenshot", + "mcp__puppeteer__puppeteer_evaluate" + ], + "deny": [] + } +} \ No newline at end of file diff --git a/claude-code-full-guide/.devcontainer/Dockerfile b/claude-code-full-guide/.devcontainer/Dockerfile new file mode 100644 index 0000000..af83a55 --- /dev/null +++ b/claude-code-full-guide/.devcontainer/Dockerfile @@ -0,0 +1,78 @@ +FROM node:20 + +ARG TZ +ENV TZ="$TZ" + +# Install basic development tools and iptables/ipset +RUN apt update && apt install -y less \ + git \ + procps \ + sudo \ + fzf \ + zsh \ + man-db \ + unzip \ + gnupg2 \ + gh \ + iptables \ + ipset \ + iproute2 \ + dnsutils \ + aggregate \ + jq + +# Ensure default node user has access to /usr/local/share +RUN mkdir -p /usr/local/share/npm-global && \ + chown -R node:node /usr/local/share + +ARG USERNAME=node + +# Persist bash history. +RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \ + && mkdir /commandhistory \ + && touch /commandhistory/.bash_history \ + && chown -R $USERNAME /commandhistory + +# Set `DEVCONTAINER` environment variable to help with orientation +ENV DEVCONTAINER=true + +# Create workspace and config directories and set permissions +RUN mkdir -p /workspace /home/node/.claude && \ + chown -R node:node /workspace /home/node/.claude + +WORKDIR /workspace + +RUN ARCH=$(dpkg --print-architecture) && \ + wget "https://github.com/dandavison/delta/releases/download/0.18.2/git-delta_0.18.2_${ARCH}.deb" && \ + sudo dpkg -i "git-delta_0.18.2_${ARCH}.deb" && \ + rm "git-delta_0.18.2_${ARCH}.deb" + +# Set up non-root user +USER node + +# Install global packages +ENV NPM_CONFIG_PREFIX=/usr/local/share/npm-global +ENV PATH=$PATH:/usr/local/share/npm-global/bin + +# Set the default shell to zsh rather than sh +ENV SHELL=/bin/zsh + +# Default powerline10k theme +RUN sh -c "$(wget -O- https://github.com/deluan/zsh-in-docker/releases/download/v1.2.0/zsh-in-docker.sh)" -- \ + -p git \ + -p fzf \ + -a "source /usr/share/doc/fzf/examples/key-bindings.zsh" \ + -a "source /usr/share/doc/fzf/examples/completion.zsh" \ + -a "export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \ + -x + +# Install Claude +RUN npm install -g @anthropic-ai/claude-code + +# Copy and set up firewall script +COPY init-firewall.sh /usr/local/bin/ +USER root +RUN chmod +x /usr/local/bin/init-firewall.sh && \ + echo "node ALL=(root) NOPASSWD: /usr/local/bin/init-firewall.sh" > /etc/sudoers.d/node-firewall && \ + chmod 0440 /etc/sudoers.d/node-firewall +USER node \ No newline at end of file diff --git a/claude-code-full-guide/.devcontainer/devcontainer.json b/claude-code-full-guide/.devcontainer/devcontainer.json new file mode 100644 index 0000000..89cff24 --- /dev/null +++ b/claude-code-full-guide/.devcontainer/devcontainer.json @@ -0,0 +1,52 @@ +{ + "name": "Claude Code Sandbox", + "build": { + "dockerfile": "Dockerfile", + "args": { + "TZ": "${localEnv:TZ:America/Los_Angeles}" + } + }, + "runArgs": [ + "--cap-add=NET_ADMIN", + "--cap-add=NET_RAW" + ], + "customizations": { + "vscode": { + "extensions": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "eamodio.gitlens" + ], + "settings": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, + "terminal.integrated.defaultProfile.linux": "zsh", + "terminal.integrated.profiles.linux": { + "bash": { + "path": "bash", + "icon": "terminal-bash" + }, + "zsh": { + "path": "zsh" + } + } + } + } + }, + "remoteUser": "node", + "mounts": [ + "source=claude-code-bashhistory,target=/commandhistory,type=volume", + "source=claude-code-config,target=/home/node/.claude,type=volume" + ], + "remoteEnv": { + "NODE_OPTIONS": "--max-old-space-size=4096", + "CLAUDE_CONFIG_DIR": "/home/node/.claude", + "POWERLEVEL9K_DISABLE_GITSTATUS": "true" + }, + "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=delegated", + "workspaceFolder": "/workspace", + "postCreateCommand": "sudo /usr/local/bin/init-firewall.sh" + } \ No newline at end of file diff --git a/claude-code-full-guide/.devcontainer/init-firewall.sh b/claude-code-full-guide/.devcontainer/init-firewall.sh new file mode 100644 index 0000000..ea63ff8 --- /dev/null +++ b/claude-code-full-guide/.devcontainer/init-firewall.sh @@ -0,0 +1,118 @@ +#!/bin/bash +set -euo pipefail # Exit on error, undefined vars, and pipeline failures +IFS=$'\n\t' # Stricter word splitting + +# Flush existing rules and delete existing ipsets +iptables -F +iptables -X +iptables -t nat -F +iptables -t nat -X +iptables -t mangle -F +iptables -t mangle -X +ipset destroy allowed-domains 2>/dev/null || true + +# First allow DNS and localhost before any restrictions +# Allow outbound DNS +iptables -A OUTPUT -p udp --dport 53 -j ACCEPT +# Allow inbound DNS responses +iptables -A INPUT -p udp --sport 53 -j ACCEPT +# Allow outbound SSH +iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT +# Allow inbound SSH responses +iptables -A INPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT +# Allow localhost +iptables -A INPUT -i lo -j ACCEPT +iptables -A OUTPUT -o lo -j ACCEPT + +# Create ipset with CIDR support +ipset create allowed-domains hash:net + +# Fetch GitHub meta information and aggregate + add their IP ranges +echo "Fetching GitHub IP ranges..." +gh_ranges=$(curl -s https://api.github.com/meta) +if [ -z "$gh_ranges" ]; then + echo "ERROR: Failed to fetch GitHub IP ranges" + exit 1 +fi + +if ! echo "$gh_ranges" | jq -e '.web and .api and .git' >/dev/null; then + echo "ERROR: GitHub API response missing required fields" + exit 1 +fi + +echo "Processing GitHub IPs..." +while read -r cidr; do + if [[ ! "$cidr" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]]; then + echo "ERROR: Invalid CIDR range from GitHub meta: $cidr" + exit 1 + fi + echo "Adding GitHub range $cidr" + ipset add allowed-domains "$cidr" +done < <(echo "$gh_ranges" | jq -r '(.web + .api + .git)[]' | aggregate -q) + +# Resolve and add other allowed domains +for domain in \ + "registry.npmjs.org" \ + "api.anthropic.com" \ + "sentry.io" \ + "statsig.anthropic.com" \ + "statsig.com"; do + echo "Resolving $domain..." + ips=$(dig +short A "$domain") + if [ -z "$ips" ]; then + echo "ERROR: Failed to resolve $domain" + exit 1 + fi + + while read -r ip; do + if [[ ! "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then + echo "ERROR: Invalid IP from DNS for $domain: $ip" + exit 1 + fi + echo "Adding $ip for $domain" + ipset add allowed-domains "$ip" + done < <(echo "$ips") +done + +# Get host IP from default route +HOST_IP=$(ip route | grep default | cut -d" " -f3) +if [ -z "$HOST_IP" ]; then + echo "ERROR: Failed to detect host IP" + exit 1 +fi + +HOST_NETWORK=$(echo "$HOST_IP" | sed "s/\.[0-9]*$/.0\/24/") +echo "Host network detected as: $HOST_NETWORK" + +# Set up remaining iptables rules +iptables -A INPUT -s "$HOST_NETWORK" -j ACCEPT +iptables -A OUTPUT -d "$HOST_NETWORK" -j ACCEPT + +# Set default policies to DROP first +iptables -P INPUT DROP +iptables -P FORWARD DROP +iptables -P OUTPUT DROP + +# First allow established connections for already approved traffic +iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT +iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT + +# Then allow only specific outbound traffic to allowed domains +iptables -A OUTPUT -m set --match-set allowed-domains dst -j ACCEPT + +echo "Firewall configuration complete" +echo "Verifying firewall rules..." +if curl --connect-timeout 5 https://example.com >/dev/null 2>&1; then + echo "ERROR: Firewall verification failed - was able to reach https://example.com" + exit 1 +else + echo "Firewall verification passed - unable to reach https://example.com as expected" +fi + +# Verify GitHub API access +if ! curl --connect-timeout 5 https://api.github.com/zen >/dev/null 2>&1; then + echo "ERROR: Firewall verification failed - unable to reach https://api.github.com" + exit 1 +else + echo "Firewall verification passed - able to reach https://api.github.com as expected" +fi \ No newline at end of file diff --git a/claude-code-full-guide/CLAUDE.md b/claude-code-full-guide/CLAUDE.md new file mode 100644 index 0000000..2a2bffe --- /dev/null +++ b/claude-code-full-guide/CLAUDE.md @@ -0,0 +1,759 @@ +# CLAUDE.md + +This file provides comprehensive guidance to Claude Code when working with Python code in this repository. + +## Core Development Philosophy + +### KISS (Keep It Simple, Stupid) + +Simplicity should be a key goal in design. Choose straightforward solutions over complex ones whenever possible. Simple solutions are easier to understand, maintain, and debug. + +### YAGNI (You Aren't Gonna Need It) + +Avoid building functionality on speculation. Implement features only when they are needed, not when you anticipate they might be useful in the future. + +### Design Principles + +- **Dependency Inversion**: High-level modules should not depend on low-level modules. Both should depend on abstractions. +- **Open/Closed Principle**: Software entities should be open for extension but closed for modification. +- **Single Responsibility**: Each function, class, and module should have one clear purpose. +- **Fail Fast**: Check for potential errors early and raise exceptions immediately when issues occur. + +## ๐Ÿงฑ Code Structure & Modularity + +### File and Function Limits + +- **Never create a file longer than 500 lines of code**. If approaching this limit, refactor by splitting into modules. +- **Functions should be under 50 lines** with a single, clear responsibility. +- **Classes should be under 100 lines** and represent a single concept or entity. +- **Organize code into clearly separated modules**, grouped by feature or responsibility. +- **Line lenght should be max 100 characters** ruff rule in pyproject.toml +- **Use venv_linux** (the virtual environment) whenever executing Python commands, including for unit tests. + +### Project Architecture + +Follow strict vertical slice architecture with tests living next to the code they test: + +``` +src/project/ + __init__.py + main.py + tests/ + test_main.py + conftest.py + + # Core modules + database/ + __init__.py + connection.py + models.py + tests/ + test_connection.py + test_models.py + + auth/ + __init__.py + authentication.py + authorization.py + tests/ + test_authentication.py + test_authorization.py + + # Feature slices + features/ + user_management/ + __init__.py + handlers.py + validators.py + tests/ + test_handlers.py + test_validators.py + + payment_processing/ + __init__.py + processor.py + gateway.py + tests/ + test_processor.py + test_gateway.py +``` + +## ๐Ÿ› ๏ธ Development Environment + +### UV Package Management + +This project uses UV for blazing-fast Python package and environment management. + +```bash +# Install UV (if not already installed) +curl -LsSf https://astral.sh/uv/install.sh | sh + +# Create virtual environment +uv venv + +# Sync dependencies +uv sync + +# Add a package ***NEVER UPDATE A DEPENDENCY DIRECTLY IN PYPROJECT.toml*** +# ALWAYS USE UV ADD +uv add requests + +# Add development dependency +uv add --dev pytest ruff mypy + +# Remove a package +uv remove requests + +# Run commands in the environment +uv run python script.py +uv run pytest +uv run ruff check . + +# Install specific Python version +uv python install 3.12 +``` + +### Development Commands + +```bash +# Run all tests +uv run pytest + +# Run specific tests with verbose output +uv run pytest tests/test_module.py -v + +# Run tests with coverage +uv run pytest --cov=src --cov-report=html + +# Format code +uv run ruff format . + +# Check linting +uv run ruff check . + +# Fix linting issues automatically +uv run ruff check --fix . + +# Type checking +uv run mypy src/ + +# Run pre-commit hooks +uv run pre-commit run --all-files +``` + +## ๐Ÿ“‹ Style & Conventions + +### Python Style Guide + +- **Follow PEP8** with these specific choices: + - Line length: 100 characters (set by Ruff in pyproject.toml) + - Use double quotes for strings + - Use trailing commas in multi-line structures +- **Always use type hints** for function signatures and class attributes +- **Format with `ruff format`** (faster alternative to Black) +- **Use `pydantic` v2** for data validation and settings management + +### Docstring Standards + +Use Google-style docstrings for all public functions, classes, and modules: + +```python +def calculate_discount( + price: Decimal, + discount_percent: float, + min_amount: Decimal = Decimal("0.01") +) -> Decimal: + """ + Calculate the discounted price for a product. + + Args: + price: Original price of the product + discount_percent: Discount percentage (0-100) + min_amount: Minimum allowed final price + + Returns: + Final price after applying discount + + Raises: + ValueError: If discount_percent is not between 0 and 100 + ValueError: If final price would be below min_amount + + Example: + >>> calculate_discount(Decimal("100"), 20) + Decimal('80.00') + """ +``` + +### Naming Conventions + +- **Variables and functions**: `snake_case` +- **Classes**: `PascalCase` +- **Constants**: `UPPER_SNAKE_CASE` +- **Private attributes/methods**: `_leading_underscore` +- **Type aliases**: `PascalCase` +- **Enum values**: `UPPER_SNAKE_CASE` + +## ๐Ÿงช Testing Strategy + +### Test-Driven Development (TDD) + +1. **Write the test first** - Define expected behavior before implementation +2. **Watch it fail** - Ensure the test actually tests something +3. **Write minimal code** - Just enough to make the test pass +4. **Refactor** - Improve code while keeping tests green +5. **Repeat** - One test at a time + +### Testing Best Practices + +```python +# Always use pytest fixtures for setup +import pytest +from datetime import datetime + +@pytest.fixture +def sample_user(): + """Provide a sample user for testing.""" + return User( + id=123, + name="Test User", + email="test@example.com", + created_at=datetime.now() + ) + +# Use descriptive test names +def test_user_can_update_email_when_valid(sample_user): + """Test that users can update their email with valid input.""" + new_email = "newemail@example.com" + sample_user.update_email(new_email) + assert sample_user.email == new_email + +# Test edge cases and error conditions +def test_user_update_email_fails_with_invalid_format(sample_user): + """Test that invalid email formats are rejected.""" + with pytest.raises(ValidationError) as exc_info: + sample_user.update_email("not-an-email") + assert "Invalid email format" in str(exc_info.value) +``` + +### Test Organization + +- Unit tests: Test individual functions/methods in isolation +- Integration tests: Test component interactions +- End-to-end tests: Test complete user workflows +- Keep test files next to the code they test +- Use `conftest.py` for shared fixtures +- Aim for 80%+ code coverage, but focus on critical paths + +## ๐Ÿšจ Error Handling + +### Exception Best Practices + +```python +# Create custom exceptions for your domain +class PaymentError(Exception): + """Base exception for payment-related errors.""" + pass + +class InsufficientFundsError(PaymentError): + """Raised when account has insufficient funds.""" + def __init__(self, required: Decimal, available: Decimal): + self.required = required + self.available = available + super().__init__( + f"Insufficient funds: required {required}, available {available}" + ) + +# Use specific exception handling +try: + process_payment(amount) +except InsufficientFundsError as e: + logger.warning(f"Payment failed: {e}") + return PaymentResult(success=False, reason="insufficient_funds") +except PaymentError as e: + logger.error(f"Payment error: {e}") + return PaymentResult(success=False, reason="payment_error") + +# Use context managers for resource management +from contextlib import contextmanager + +@contextmanager +def database_transaction(): + """Provide a transactional scope for database operations.""" + conn = get_connection() + trans = conn.begin_transaction() + try: + yield conn + trans.commit() + except Exception: + trans.rollback() + raise + finally: + conn.close() +``` + +### Logging Strategy + +```python +import logging +from functools import wraps + +# Configure structured logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) + +logger = logging.getLogger(__name__) + +# Log function entry/exit for debugging +def log_execution(func): + @wraps(func) + def wrapper(*args, **kwargs): + logger.debug(f"Entering {func.__name__}") + try: + result = func(*args, **kwargs) + logger.debug(f"Exiting {func.__name__} successfully") + return result + except Exception as e: + logger.exception(f"Error in {func.__name__}: {e}") + raise + return wrapper +``` + +## ๐Ÿ”ง Configuration Management + +### Environment Variables and Settings + +```python +from pydantic_settings import BaseSettings +from functools import lru_cache + +class Settings(BaseSettings): + """Application settings with validation.""" + app_name: str = "MyApp" + debug: bool = False + database_url: str + redis_url: str = "redis://localhost:6379" + api_key: str + max_connections: int = 100 + + class Config: + env_file = ".env" + env_file_encoding = "utf-8" + case_sensitive = False + +@lru_cache() +def get_settings() -> Settings: + """Get cached settings instance.""" + return Settings() + +# Usage +settings = get_settings() +``` + +## ๐Ÿ—๏ธ Data Models and Validation + +### Example Pydantic Models strict with pydantic v2 + +```python +from pydantic import BaseModel, Field, validator, EmailStr +from datetime import datetime +from typing import Optional, List +from decimal import Decimal + +class ProductBase(BaseModel): + """Base product model with common fields.""" + name: str = Field(..., min_length=1, max_length=255) + description: Optional[str] = None + price: Decimal = Field(..., gt=0, decimal_places=2) + category: str + tags: List[str] = [] + + @validator('price') + def validate_price(cls, v): + if v > Decimal('1000000'): + raise ValueError('Price cannot exceed 1,000,000') + return v + + class Config: + json_encoders = { + Decimal: str, + datetime: lambda v: v.isoformat() + } + +class ProductCreate(ProductBase): + """Model for creating new products.""" + pass + +class ProductUpdate(BaseModel): + """Model for updating products - all fields optional.""" + name: Optional[str] = Field(None, min_length=1, max_length=255) + description: Optional[str] = None + price: Optional[Decimal] = Field(None, gt=0, decimal_places=2) + category: Optional[str] = None + tags: Optional[List[str]] = None + +class Product(ProductBase): + """Complete product model with database fields.""" + id: int + created_at: datetime + updated_at: datetime + is_active: bool = True + + class Config: + from_attributes = True # Enable ORM mode +``` + +## ๐Ÿ”„ Git Workflow + +### Branch Strategy + +- `main` - Production-ready code +- `develop` - Integration branch for features +- `feature/*` - New features +- `fix/*` - Bug fixes +- `docs/*` - Documentation updates +- `refactor/*` - Code refactoring +- `test/*` - Test additions or fixes + +### Commit Message Format + +Never include claude code, or written by claude code in commit messages + +``` +(): + + + +