Skip to content

Development Guidelines - PCB Stackup Generator

Internal Use Only - This document provides development guidelines, code style requirements, and best practices for the internal development team. This is a proprietary project, not open source.

Table of Contents

Getting Started

Prerequisites

  • Node.js (v18 or later)
  • Python 3.9+ (for backend)
  • KiCad 10.0 (for full symbol generation)
  • Git for version control

Setup

  1. Clone the repository (internal access required):

    git clone [internal-repository-url]
    cd pcb_stackup_generator
    

  2. Install dependencies:

    # Frontend
    cd frontend
    npm install
    
    # Backend
    cd ../backend
    pip install -r requirements.txt
    

  3. Set up pre-commit hooks:

    pip install pre-commit
    pre-commit install
    

  4. Configure environment variables:

  5. Copy env.production.template to .env in project root or config/.env
  6. Fill in required values (see ENV_VARIABLES_GUIDE.md)

  7. Start development servers:

    .\start-all-servers-windowed.ps1
    

Critical Development Rules

  • Database rule: Backend is the only source of truth. Edit only backend/categorized_databases/. Do not run update_frontend_database.py (deprecated). Frontend uses the backend API; no sync step is needed.
  • KiCad Python: Use C:\Program Files\KiCad\10.0\bin\python.exe for any script that imports pcbnew or eeschema. System Python does not have these modules.
  • Startup: Always use .\start-all-servers-windowed.ps1. Do not start servers manually (e.g. node index.js); the script handles ports, env vars, and database preloading.

See CLAUDE.md for full details.

Code Style Guidelines

General Principles

  • Keep files under 300 lines - Split into modules when approaching this limit
  • Never create files longer than 500 lines - This is a hard limit
  • Test early, test often - Write tests for all new functions
  • Document as you go - Don't delay documentation

Python (Backend) Style

Naming Conventions

  • Files: snake_case.py (e.g., email_service.py, validated_database_service.py)
  • Functions: snake_case() (e.g., get_components(), validate_input())
  • Classes: PascalCase (e.g., ValidatedDatabaseService, ProjectCreate)
  • Variables: snake_case (e.g., user_id, component_list)
  • Constants: UPPER_SNAKE_CASE (e.g., SUPABASE_URL, API_KEYS)
  • Private functions: Prefix with _ (e.g., _internal_helper())

Code Formatting

  • Follow PEP 8 guidelines
  • Use Ruff for linting and formatting:
    ruff check --fix .
    ruff format .
    
  • Type hints required for all function parameters and return values:
    def get_component(category: str, frequency: float) -> Optional[dict]:
        """Get component by category and frequency."""
        pass
    

Docstrings

Start docstrings with an Intent statement: 1-2 sentences describing what the function achieves from a business/domain perspective. This aids AI-assisted debugging.

Use Google-style docstrings for all functions:

def calculate_power_flow(
    components: list[dict],
    input_power: float
) -> dict[str, float]:
    """Calculate RF power flow through component chain.

    Intent: Given a list of RF components and input power, compute power levels
    at each stage for link budget analysis. Used by BOM validation and chain design.

    Args:
        components: List of RF components with gain/loss values.
        input_power: Input power in dBm.

    Returns:
        Dictionary with power levels at each stage:
        - 'stages': List of power levels
        - 'output_power': Final output power in dBm
        - 'total_gain': Total gain in dB

    Raises:
        ValueError: If input_power is negative or components list is empty.
    """
    pass

Comments

  • Comment non-obvious code with explanations of "why", not just "what"
  • Add "# Reason:" comments for complex logic:
    # Reason: Two-pass optimization needed to find ideal margin (1.3 dB)
    # without excessive over-design
    for iteration in range(2):
        vco = select_vco_with_margin(target_freq, margin=1.3)
    

TypeScript/React (Frontend) Style

Naming Conventions

  • Files: camelCase.ts or camelCase.tsx (e.g., componentDatabaseService.ts, projectCard.tsx)
  • Components: PascalCase (e.g., ProjectCard, PhaseProvider)
  • Functions: camelCase() (e.g., saveProject(), loadComponent())
  • Interfaces: PascalCase (e.g., ProjectCardProps, RfChainComponent)
  • Types: PascalCase (e.g., ProjectMetadata, PhaseState)
  • Hooks: camelCase with "use" prefix (e.g., usePhaseContext(), useRfModuleState())
  • Constants: camelCase or UPPER_SNAKE_CASE (e.g., apiBaseURL, SUPABASE_URL)
  • Private functions: Prefix with _ (e.g., _internalHelper())

Code Formatting

  • Use Prettier for formatting (if configured)
  • Follow ESLint rules
  • Use TypeScript strict mode
  • Prefer functional components with hooks

Function Documentation

/**
 * Selects optimal VCO for given frequency requirements.
 * 
 * @param frequency - Target frequency in Hz
 * @param application - Application type (Consumer, Automotive, RF/Microwave)
 * @param customWeights - Optional custom selection weights
 * @returns Selected VCO component or null if none found
 * @throws {Error} If frequency is out of valid range
 */
async function selectVCO(
  frequency: number,
  application: RfApplicationType,
  customWeights?: VCOWeights
): Promise<RfChainComponent | null> {
  // Implementation
}

File Organization

  • Keep related code together - Group by feature, not by type
  • Use barrel exports - Create index.ts files for clean imports
  • Separate concerns - Business logic in services, UI in components
  • Follow existing patterns - Match the structure of similar files

Documentation Requirements

Code Documentation

  1. All exported/public functions must have docstrings/comments:
  2. Python: Google-style docstrings
  3. TypeScript: JSDoc comments

  4. Complex logic must have inline comments:

    # Reason: Two-pass selection needed because first pass may over-estimate
    # required margin, leading to unnecessarily expensive components
    

  5. Update README.md when:

  6. Adding new features
  7. Changing dependencies
  8. Modifying setup steps
  9. Adding new environment variables

Service Documentation

When adding new services:

  1. Update service README:
  2. See GitHub repository for component services
  3. See GitHub repository for RF chain services
  4. See GitHub repository for backend services

  5. Document in main README:

  6. Add to architecture overview
  7. Update service list
  8. Add usage examples if applicable

API Documentation

  • FastAPI endpoints are auto-documented, but add clear descriptions:
    @router.get("/components/vco", summary="Search VCO components")
    async def search_vco(
        frequency: float = Query(..., description="Target frequency in Hz"),
        application: str = Query(..., description="Application type")
    ):
        """Search for VCO components matching frequency and application."""
        pass
    

Testing Requirements

Test Coverage

Every new function must have unit tests with at least:

  1. Expected use case - Normal operation
  2. Edge case - Boundary conditions
  3. Failure case - Error handling

Python Tests

  • Use pytest for all tests
  • Use pytest-asyncio for async functions
  • Tests in backend/tests/ mirror main structure
  • Name tests: test_[function_name]_[scenario].py
import pytest
from services.validated_database_service import validated_db_service

def test_get_components_by_category_success():
    """Test successful component retrieval."""
    components = validated_db_service.get_components_by_category('vco')
    assert len(components) > 0
    assert all(c['category'] == 'vco' for c in components)

def test_get_components_by_category_invalid():
    """Test invalid category handling."""
    with pytest.raises(ValueError):
        validated_db_service.get_components_by_category('invalid')

TypeScript Tests

  • Use Vitest for frontend tests
  • Tests in frontend/src/**/__tests__/
  • Test components, hooks, and services
import { selectVCO } from './vcoSelectionService';

describe('selectVCO', () => {
  it('should select VCO for valid frequency', async () => {
    const vco = await selectVCO(2.4e9, 'Consumer');
    expect(vco).toBeDefined();
    expect(vco?.frequency_min).toBeLessThanOrEqual(2.4e9);
    expect(vco?.frequency_max).toBeGreaterThanOrEqual(2.4e9);
  });

  it('should return null for invalid frequency', async () => {
    const vco = await selectVCO(-1, 'Consumer');
    expect(vco).toBeNull();
  });
});

Running Tests

# Python tests
cd backend
pytest

# Frontend tests
cd frontend
npm test

Code Review Process

Before Submitting for Review

  1. Check existing work - Avoid duplicates with current tasks
  2. Update documentation - README, service docs, API docs
  3. Write/update tests - Ensure all tests pass
  4. Run linters - Fix all linting errors
  5. Test locally - Verify functionality works
  6. Update CHANGELOG (if applicable)

Merge Request Title Format

Use clear, descriptive titles: - feat: Add VCO selection optimization - fix: Resolve power flow calculation error - docs: Update component selection documentation - refactor: Split large service into modules

Merge Request Description Template

## Description
Brief description of changes.

## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Documentation update
- [ ] Refactoring
- [ ] Performance improvement

## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests pass
- [ ] Manual testing completed

## Documentation
- [ ] README updated
- [ ] Service documentation updated
- [ ] API documentation updated
- [ ] Code comments added

## Checklist
- [ ] Code follows style guidelines
- [ ] All tests pass
- [ ] No linting errors
- [ ] Documentation updated

Merge Request Checklist

Before submitting a merge request, ensure:

Code Quality

  • Code follows naming conventions
  • Files are under 300 lines (or split appropriately)
  • Type hints added (Python) / Types defined (TypeScript)
  • No hardcoded secrets or credentials
  • Error handling implemented
  • No console.log/debug statements left in code

Documentation

  • All functions have docstrings/comments
  • Complex logic has "# Reason:" comments
  • README.md updated if needed
  • Service documentation updated
  • API documentation updated (if applicable)

Testing

  • Unit tests written for new functions
  • Edge cases tested
  • Error cases tested
  • All existing tests still pass
  • Manual testing completed

Style & Linting

  • Ruff/Python formatting applied (ruff format .)
  • Ruff linting passes (ruff check .)
  • TypeScript/ESLint passes
  • Pre-commit hooks pass

Git

  • Meaningful commit messages
  • Logical commit history (use rebase if needed)
  • Branch is up to date with main
  • No merge conflicts

Functionality

  • Feature works as expected
  • No breaking changes (or documented if intentional)
  • Backward compatibility maintained
  • Performance acceptable

Project Structure

Key Directories

pcb_stackup_generator/
├── frontend/              # React/TypeScript frontend
│   └── src/
│       ├── services/     # Business logic services
│       ├── components/   # UI components
│       ├── hooks/        # React hooks
│       └── utils/        # Utility functions
├── backend/              # Python FastAPI backend
│   ├── services/         # Backend services
│   ├── routes/           # API routes
│   ├── agents/           # AI agent implementations
│   └── categorized_databases/  # Component databases
├── docs/                 # Project documentation
└── scripts/             # Utility scripts

Important Files

  • README.md - Main project documentation
  • DEVELOPMENT_GUIDELINES.md - This file
  • .cursor/rules/general-rule.mdc - Project-specific rules
  • PLANNING.md - Architecture and planning docs
  • TASK.md - Task tracking

Development Workflow

1. Create Feature Branch

git checkout -b feature/your-feature-name

2. Make Changes

  • Write code following style guidelines
  • Add tests as you go
  • Update documentation
  • Commit frequently with clear messages

3. Test Locally

# Run all tests
pytest backend/tests
npm test -- frontend

# Run linters
ruff check --fix .
ruff format .

# Start servers and test manually
.\start-all-servers-windowed.ps1

4. Update Documentation

  • Update relevant README files
  • Add/update service documentation
  • Update API docs if needed

5. Submit for Review

  • Push to your branch
  • Create merge request with description
  • Link related tasks/issues
  • Request review from team

6. Address Feedback

  • Respond to review comments
  • Make requested changes
  • Update merge request as needed

Code Patterns to Follow

Pattern 1: Service Layer Architecture

Purpose: Separate business logic from UI components

// CORRECT: Logic in service
// services/rfChain/powerCalculator.ts
export const calculateRfPower = (
  inputPower: number,
  gain: number,
  loss: number
): number => {
  return inputPower + gain - loss; // dBm calculation
};

// components/PowerDisplay.tsx
import { calculateRfPower } from '../../services/rfChain/powerCalculator';

const PowerDisplay = ({ inputPower, gain, loss }) => {
  const outputPower = calculateRfPower(inputPower, gain, loss);
  return <div>Output: {outputPower} dBm</div>;
};

Pattern 2: Context Splitting

Purpose: Reduce re-renders by separating data from actions

// CORRECT: Split contexts
// contexts/RfModuleDataContext.tsx
export const RfModuleDataContext = createContext<RfModuleData | null>(null);

// contexts/RfModuleActionsContext.tsx
export const RfModuleActionsContext = createContext<RfModuleActions | null>(null);

// Usage: data re-renders only on data changes; actions are stable reference

Pattern 3: Barrel Exports

Purpose: Cleaner imports and better organization

// CORRECT: services/index.ts
export * from './stackup/impedanceCalculator';
export * from './stackup/stackupService';
export * from './rfChain/powerCalculator';

// Usage
import { calculateImpedance, generateStackup, calculateRfPower } from '../services';

Pattern 4: Error Handling with Fallbacks

Purpose: Graceful degradation and user-friendly errors

# CORRECT: Fallback mechanism
try:
    results = await nexar_api.search(request.query)
    return results
except NexarAPIError as e:
    logger.warning(f"Nexar failed: {e}, falling back to validated database")
    return validated_db.search(request.query)
except Exception as e:
    logger.error(f"Search failed: {e}")
    raise HTTPException(status_code=500, detail="Component search unavailable")

Pattern 5: TypeScript Strict Typing

Purpose: Catch errors at compile time

// CORRECT: Strong typing
interface Component {
  part_number: string;
  frequency_min_ghz: number;
  frequency_max_ghz: number;
  gain_db?: number;
}

const filterByFrequency = (
  components: Component[],
  targetFreq: number
): Component[] => {
  return components.filter(c =>
    c.frequency_min_ghz <= targetFreq &&
    c.frequency_max_ghz >= targetFreq
  );
};

Environment Variables

Never commit .env files!

  • Use env.production.template as reference
  • Document new variables in ENV_VARIABLES_GUIDE.md
  • Use environment variables for all secrets/config

Security

  • Never hardcode API keys or credentials
  • Use environment variables for sensitive data
  • Validate all user inputs
  • Sanitize outputs to prevent injection
  • Follow security best practices (see SECURITY_TESTING_GUIDE.md)

Getting Help

  • Documentation: Check docs/ directory
  • Team Communication: Contact team lead or project manager
  • Questions: Reach out to senior developers or check existing documentation
  • Internal Resources: Refer to internal project management tools

Code Review Guidelines

For Reviewers

  • Be constructive and respectful
  • Focus on code quality, not personal preferences
  • Explain reasoning for requested changes
  • Approve when requirements are met

For Authors

  • Respond to all comments
  • Don't take feedback personally
  • Ask for clarification if needed
  • Make requested changes or explain why not

Additional Resources


These guidelines help maintain code quality and consistency across the development team. 🚀