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 .
    
  • Unused imports are deleted at commit (ruff rule F401, issue 234). An import kept only so OTHER files can import the name from here looks unused to ruff, so mark it (__all__, or # noqa: F401 with the reason) or ruff will delete it. To find any it would delete: bash scripts/hook-tool.sh python backend/scripts/check_hidden_reexports.py.
  • 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)

Upgrading Dependencies

  • GitHub keeps two pip snapshots of this repo: one scanned from the repo root, which also reads backend/requirements*.txt, and one scanned from /backend.
  • A PR that changes only backend/requirements*.txt refreshes only the /backend snapshot, so the Dependabot alerts it fixes stay open.
  • When only backend requirements change, also change a root pip file (usually a comment line in docs-requirements.txt) so GitHub re-scans from the root. See the comment at the top of that file.
  • This has been proven twice with a follow-up PR (issues 113 and 223). Doing it in the same PR is not verified.
  • After merging, check that the old version is gone: gh api repos/magiccadai/AI-assisted-PCB-stackup-generator/dependency-graph/sbom should no longer list it next to the new one (issue 391).

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. 🚀