Carlos Eduardo Gatti Ferreira

Coding Conventions

This document outlines coding standards, naming conventions, and best practices used throughout the monorepo.

TypeScript Conventions

Type Definitions

Prefer interfaces for objects:

interface User {
  id: string;
  email: string;
  firstName: string;
}

// Use for props, API responses, data structures

Use type aliases for unions/intersections:

type ItemStatus = 'ACTIVE' | 'SOLD' | 'REMOVED';
type UserWithToken = User & { token: string };

File naming:

Type Safety


React Conventions

Component Structure

Functional components only:

export function MyComponent({ prop1, prop2 }: MyComponentProps) {
  // Hooks
  const [state, setState] = useState();
  
  // Effects
  useEffect(() => {}, []);
  
  // Handlers
  const handleClick = () => {};
  
  // Render
  return <div>...</div>;
}

Component naming:

File organization:

// 1. Imports (external, then internal)
import { useState } from 'react';
import { Button } from '@/components/ui';
import { useAuth } from '@/src/features/auth/useAuth';

// 2. Types
interface MyComponentProps {
  title: string;
}

// 3. Component
export function MyComponent({ title }: MyComponentProps) {
  // ...
}

// 4. Sub-components (if needed)
function SubComponent() {
  // ...
}

Hooks

Naming:

Custom hook structure:

export function useMyHook(dependency: string) {
  const [state, setState] = useState<State>(initialState);
  
  useEffect(() => {
    // Side effects
  }, [dependency]);
  
  const action = useCallback(() => {
    // Action logic
  }, []);
  
  return { state, action };
}

Rules:


File & Folder Naming

Files

Components: PascalCase.tsx

Utilities: camelCase.ts

Hooks: camelCase.ts with use prefix

Types: camelCase.types.ts or types.ts

Constants: camelCase.ts

Folders

Components: kebab-case or camelCase

Features: kebab-case

Apps: kebab-case


Import Organization

Order

  1. React and Next.js
  2. External libraries
  3. Internal shared code (@/src, @/components)
  4. Relative imports
  5. Types (if separate)

Example:

// 1. React/Next.js
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';

// 2. External
import clsx from 'clsx';
import { toast } from 'sonner';

// 3. Internal shared
import { Button } from '@/components/ui';
import { useAuth } from '@/src/features/auth/useAuth';
import { processImage } from '@/src/lib/image';

// 4. Relative
import { MySubComponent } from './MySubComponent';
import { styles } from './styles.module.css';

// 5. Types (if separate)
import type { User } from '@/src/types';

Path Aliases

Always use path aliases for shared code:

// ✅ Good
import { Button } from '@/components/ui';
import { useAuth } from '@/src/features/auth/useAuth';

// ❌ Avoid
import { Button } from '../../../components/ui';

Relative imports for same feature:

// ✅ Good (same feature)
import { SubComponent } from './SubComponent';

// ✅ Good (shared code)
import { Button } from '@/components/ui';

Code Organization

Feature Modules

Structure:

features/
  my-feature/
    ├── components/        # Feature-specific UI
    │   └── MyComponent.tsx
    ├── hooks/            # Feature-specific logic
    │   └── useMyFeature.ts
    ├── types.ts          # Feature types
    └── index.ts          # Public exports (optional)

Guidelines:

Utility Functions

Location: src/lib/{category}/

Structure:

lib/
  image/
    ├── processImage.ts   # Main function
    ├── utils.ts          # Helpers
    ├── constants.ts      # Constants
    ├── types.ts          # Types
    └── index.ts          # Public exports

Guidelines:


Styling Conventions

Tailwind CSS

Prefer utility classes:

// ✅ Good
<div className="flex items-center gap-4 p-6 bg-zinc-900 rounded-xl">
  <Button variant="primary">Click</Button>
</div>

// ❌ Avoid inline styles
<div style=>

Extract to components for reusability:

// ✅ Good (reusable)
<Card>
  <Button variant="primary">Click</Button>
</Card>

// ❌ Avoid (repeated utilities)
<div className="p-6 bg-zinc-900 rounded-xl border border-zinc-800">
  <Button variant="primary">Click</Button>
</div>

Responsive design:

// ✅ Good
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
  {items.map(item => <ItemCard key={item.id} item={item} />)}
</div>

Component Styling

Use clsx for conditional classes:

import clsx from 'clsx';

<button
  className={clsx(
    'px-4 py-2 rounded-lg',
    isActive && 'bg-blue-500 text-white',
    isDisabled && 'opacity-50 cursor-not-allowed'
  )}
>
  Click
</button>

Use tailwind-merge when merging classes:

import { cn } from '@/src/lib/utils'; // wrapper around tailwind-merge

<Button className={cn('px-6', props.className)}>
  Click
</Button>

API Client Conventions

Function Naming

REST APIs:

GraphQL:

Error Handling

Always handle errors:

try {
  const items = await getItems();
  setItems(items);
} catch (error) {
  console.error('Failed to fetch items:', error);
  toast.error('Could not load items. Please try again.');
}

Error messages:


State Management Conventions

Local State

Use useState for component state:

const [isOpen, setIsOpen] = useState(false);
const [items, setItems] = useState<Item[]>([]);

Use useReducer for complex state (if needed):

const [state, dispatch] = useReducer(reducer, initialState);

Global State

Use Context for app-wide state:

// Auth, theme, user preferences
const { user, login, logout } = useAuth();

Use React Query for server state:

const { data, isLoading, error } = useQuery({
  queryKey: ['items'],
  queryFn: () => getItems(),
});

Documentation Conventions

Code Comments

Explain “why”, not “what”:

// ❌ Bad (obvious)
// Set isOpen to true
setIsOpen(true);

// ✅ Good (explains why)
// Auto-close modal after 3 seconds to prevent accidental submissions
setTimeout(() => setIsOpen(false), 3000);

JSDoc for public APIs:

/**
 * Process and compress an image file
 * @param file - Input image file
 * @param options - Processing options (maxWidth, quality, etc.)
 * @returns Processed image with metadata
 */
export function processImage(file: File, options: ImageProcessingOptions): Promise<ProcessedImage> {
  // ...
}

README Files

Required for:

Should include:


Testing Conventions (Future)

Unit Tests

Location: __tests__/ or .test.ts files

Naming: {file}.test.ts

Structure:

describe('processImage', () => {
  it('should resize image to max width', async () => {
    // Test
  });
  
  it('should compress image to target size', async () => {
    // Test
  });
});

Git Conventions

Commit Messages

Format: type(scope): message

Types:

Examples:

feat(qrack): add QR code scanner
fix(discart-me): image upload error handling
docs: update architecture documentation
refactor(auth): consolidate auth providers

Branch Naming

Format: {type}/{description}

Examples:


Accessibility Conventions

Semantic HTML

Use semantic elements:

// ✅ Good
<button onClick={handleClick}>Submit</button>
<nav><ul><li><a href="/">Home</a></li></ul></nav>

// ❌ Avoid
<div onClick={handleClick}>Submit</div>
<div><div><div>Home</div></div></div>

ARIA Attributes

Use when needed:

<button
  aria-label="Close dialog"
  aria-expanded={isOpen}
  onClick={handleClose}
>
  ×
</button>

Use Headless UI for complex components (has ARIA built-in)


Performance Conventions

Code Splitting

Dynamic imports for heavy dependencies:

const QRCodeScanner = dynamic(() => import('./QRCodeScanner'), {
  ssr: false,
});

Memoization

Use useMemo for expensive computations:

const filteredItems = useMemo(() => {
  return items.filter(item => item.status === 'ACTIVE');
}, [items]);

Use useCallback for stable function references:

const handleClick = useCallback(() => {
  doSomething(id);
}, [id]);