Skip to content

Style Guides

Contributing Code

Before committing or pushing changes, we aim to follow a set of standards to keep commits and changes easy to understand and meaningful. These standards are used to enhance communication between fellow contributors who write and read code for the project. Fewer chances of overthinking communication and a higher chance of shipping high quality contributions.

Commit Guidelines

We follow and extend this framework, we recommend to at least take a glance or skim through the specification. Basically, we make commits in this format: {emoji} {type} {(scope)<optional>}: {description}.

Emoji Type What it covers
πŸ“¦ new Adding new features, files, or capabilities
πŸ”§ update Changing existing code, refactoring, improvements, bug fixes
πŸ—‘οΈ remove Removing code, files, features, or dependencies
πŸ”’ security Security fixes, patches, vulnerability resolutions
βš™οΈ setup Project configs, CI/CD, tooling, build systems
β˜• chore Maintenance tasks, dependency updates, housekeeping
πŸ§ͺ test Adding, updating, or fixing tests
πŸ“– docs Documentation changes and updates
🏷️ release Version releases and release preparation

Examples

πŸ“¦ new: user authentication system
πŸ”§ update (api): improve error handling  # with optional scope
πŸ”’ security (auth): fix jwt token validation bypass
πŸ—‘οΈ remove (deps): unused axios dependency
β˜• chore (deps): bump react from 17.0.2 to 18.2.0
πŸ“– docs: fix typos in contributing guide

Conventional Comments

When communicating with fellow contributors, it is recommended to follow this format or communicate so in a similar format that is practical and direct to the point.

Backend

These are style guides for both Python code and the database schema.

Project, Folder & File Names

Rules

  • lowercase
  • snake_case
  • nouns for folders
  • verbs only when it’s an action module
  • no hyphens

Examples

app/
β”œβ”€β”€ main.py
β”œβ”€β”€ api/
β”‚   β”œβ”€β”€ v1/
β”‚   β”‚   β”œβ”€β”€ routes/
β”‚   β”‚   β”‚   β”œβ”€β”€ users.py
β”‚   β”‚   β”‚   β”œβ”€β”€ recipes.py
β”‚   β”‚   β”‚   └── auth.py
β”‚   β”‚   β”œβ”€β”€ dependencies.py
β”‚   β”‚   └── schemas/
β”‚   β”‚       β”œβ”€β”€ user.py
β”‚   β”‚       └── recipe.py
β”œβ”€β”€ core/
β”‚   β”œβ”€β”€ config.py
β”‚   β”œβ”€β”€ security.py
β”‚   └── logging.py
β”œβ”€β”€ models/
β”‚   β”œβ”€β”€ user.py
β”‚   β”œβ”€β”€ recipe.py
β”‚   └── ingredient.py
β”œβ”€β”€ services/
β”‚   β”œβ”€β”€ user_service.py
β”‚   └── recipe_service.py
β”œβ”€β”€ db/
β”‚   β”œβ”€β”€ base.py
β”‚   β”œβ”€β”€ session.py
β”‚   └── migrations/
└── tests/

Avoid

UserRoutes.py
recipe-routes.py
Controllers/

Python Class Names

Use PascalCase

  • Pydantic models
  • SQLAlchemy models
  • Service classes
  • Exceptions
class User(Base):
    ...

class RecipeCreate(BaseModel):
    ...

class RecipeService:
    ...

Avoid

class user:
class recipe_service:

Function & Method Names

Use snake_case

  • Verbs for actions
  • Clear, explicit names
def get_user_by_id(user_id: int) -> User:
    ...

def create_recipe(data: RecipeCreate) -> Recipe:
    ...

FastAPI path operations

@router.get("/{recipe_id}")
def read_recipe(recipe_id: int):
    ...

Variable Names

Rules

  • snake_case
  • Descriptive
  • Avoid abbreviations unless common (id, db, api)
user_id: int
recipe_ingredients: list[RecipeIngredient]
db_session: Session

Avoid

x
tmp
usrId

Constants

Use UPPER_SNAKE_CASE

JWT_ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

Database Table Names

  • Use snake_case

  • Use plural nouns

  • Be consistent

users
recipes
recipe_ingredients
recipe_steps
categories
stores
shelves

This matches:

  • PostgreSQL conventions
  • SQLAlchemy defaults
  • REST naming

Avoid

User
RecipeIngredient
recipeIngredients

Database Column Names

Rules

  • snake_case
  • Descriptive
  • No table name prefix
  • Avoid reserved words
id
user_id
created_at
amount_grams
amount_readable
cook_time_sec

Avoid

userId
recipeID
tbl_user_id

SQLAlchemy Model Naming (Best Practice)

Class ↔ Table mapping

class Recipe(Base):
    __tablename__ = "recipes"

    id = Column(Integer, primary_key=True)
    user_id = Column(ForeignKey("users.id"))
    title = Column(String)

Pydantic Schema Naming

Suffix-based clarity

UserBase
UserCreate
UserRead
UserUpdate

RecipeBase
RecipeCreate
RecipeRead

API Route Naming

REST-style, plural nouns

GET    /api/v1/recipes
POST   /api/v1/recipes
GET    /api/v1/recipes/{id}
PUT    /api/v1/recipes/{id}
DELETE /api/v1/recipes/{id}

Avoid

/getRecipe
/create-recipe

Test File Naming (pytest)

test_users.py
test_recipes.py
test_auth.py

Test functions:

def test_create_recipe_success():
    ...
def create_recipe(
    db: Session,
    user_id: int,
    data: RecipeCreate,
) -> Recipe:
    """Create a new recipe for a user."""

Linters & Formatters

Required

ruff
black
mypy
[tool.black]
line-length = 99

[tool.ruff]
select = ["E", "F", "B", "I"]

API response messages

Messages that contain string variable values should be single-quoted, otherwise if numeric use no quotes at all.

String response:

Something name 'something' was not found.

Numeric response:

Somethin ID 1 was not found.

Docstrings

We use the NumPy style for writing docstrigns

Golden Rule (Very Important)

Python names β†’ snake_case > Classes β†’ PascalCase > DB tables β†’ plural snake_case > DB columns β†’ snake_case