# Coding Style Rules ## Python (Backend) ### General - Python 3.12+ features encouraged (type parameter syntax, match statements where clearer). - `ruff` handles formatting and linting. Config lives in `pyproject.toml`. - `mypy` in strict mode. No `Any` types. No `# type: ignore` without a comment explaining why. ### Naming | Entity | Convention | Example | |---|---|---| | Files/modules | `snake_case` | `order_service.py` | | Functions | `snake_case` | `calculate_total()` | | Classes | `PascalCase` | `Invoice` | | Constants | `UPPER_SNAKE_CASE` | `MAX_RETRY_COUNT` | | Database columns | `snake_case` | `created_at` | | Pydantic models | `PascalCase` + suffix | `ItemCreateRequest`, `ItemResponse` | ### Functions - Max 50 lines. If longer, extract helpers. - Use early returns to avoid nesting (see Negative Space Programming below). ### Negative Space Programming (Fail Early) Reject invalid state at the top of every function. The happy path is the code that remains after all guard clauses. This applies at every layer. **Guard clauses before logic:** ```python # CORRECT - fail early, happy path is clean def process_order(quantity: int, unit_price: Decimal) -> OrderResult: if quantity <= 0: raise ValidationError("Quantity must be positive") if unit_price <= 0: raise ValidationError("Unit price must be positive") total = quantity * unit_price return OrderResult(total=total) # WRONG - nested conditionals, happy path buried def process_order(quantity: int, unit_price: Decimal) -> OrderResult: if quantity > 0: if unit_price > 0: total = quantity * unit_price return OrderResult(total=total) else: raise ValidationError("Unit price must be positive") else: raise ValidationError("Quantity must be positive") ``` **Key rules:** - Max 3 levels of indentation in any function. If deeper, extract or flatten. - Never use `else` after a `return`, `raise`, or `throw` — the guard already exited. - No silent failures: if something is wrong, raise/throw immediately with context. - Optional/nullable returns are acceptable only when "not found" is a normal case (e.g., repository lookups). For business rule violations, always raise. ### Imports - Group: stdlib -> third-party -> local. Ruff enforces this. - No wildcard imports (`from module import *`). - No relative imports across packages. Use absolute imports: `from app.module import ...`. ### Type Hints - All function signatures must have type hints (params and return). - Use `UUID` from `uuid`, not `str`, for ID fields. - Use `datetime` from `datetime`, not `str`, for timestamps. - Collections: `list[Item]`, not `List[Item]` (Python 3.12+). ## TypeScript (Frontend) ### General - Strict TypeScript. No `any`. No `@ts-ignore` without explanation. - ESLint + Prettier via the project config. No overrides in individual files. ### Naming | Entity | Convention | Example | |---|---|---| | Files (components) | `PascalCase.vue` | `OrderForm.vue` | | Files (composables) | `camelCase.ts` | `useOrderForm.ts` | | Files (utilities) | `camelCase.ts` | `formatCurrency.ts` | | Variables/functions | `camelCase` | `calculateTotal()` | | Types/interfaces | `PascalCase` | `Order` | | Constants | `UPPER_SNAKE_CASE` | `DEFAULT_PAGE_SIZE` | | Props | `camelCase` | `orderItems` | | Events | `camelCase` verb | `@submit`, `@update:modelValue` | ### Vue Components - Use `