This document outlines the coding standards and best practices for the PetChain project.
- General Principles
- TypeScript
- React/Next.js
- Styling
- File Organization
- Naming Conventions
- Git Commit Messages
- Write clean, readable code - Code is read more often than it's written
- Follow DRY - Don't Repeat Yourself
- Keep it simple - Avoid over-engineering
- Write self-documenting code - Use clear variable and function names
- Comment when necessary - Explain "why", not "what"
// ✅ Good - Explicit types
interface User {
id: string;
name: string;
email: string;
}
function getUser(id: string): User {
// implementation
}
// ❌ Bad - Using 'any'
function getUser(id: any): any {
// implementation
}- Use
interfacefor object shapes that might be extended - Use
typefor unions, intersections, and primitives
// ✅ Good
interface Pet {
id: string;
name: string;
}
type PetStatus = 'active' | 'inactive' | 'pending';// ✅ Good
const user = getUser();
if (user) {
console.log(user.name);
}
// ❌ Bad
const user = getUser();
console.log(user!.name);// ✅ Good - Functional component with TypeScript
interface ButtonProps {
label: string;
onClick: () => void;
disabled?: boolean;
}
export default function Button({ label, onClick, disabled = false }: ButtonProps) {
return (
<button onClick={onClick} disabled={disabled} className="btn">
{label}
</button>
);
}- Use hooks at the top level of components
- Custom hooks should start with "use"
- Keep hooks simple and focused
// ✅ Good
function usePetData(petId: string) {
const [pet, setPet] = useState<Pet | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchPet(petId).then(setPet).finally(() => setLoading(false));
}, [petId]);
return { pet, loading };
}// ✅ Good
function PetCard({ name, breed, age }: PetCardProps) {
return <div>{name}</div>;
}
// ❌ Bad
function PetCard(props: PetCardProps) {
return <div>{props.name}</div>;
}// ✅ Good - Clear and readable
{isLoading ? <Spinner /> : <Content />}
// ✅ Good - For simple conditions
{isVisible && <Component />}
// ❌ Bad - Nested ternaries
{isLoading ? <Spinner /> : isError ? <Error /> : <Content />}- Use Tailwind utility classes
- Group related classes together
- Use responsive prefixes consistently
// ✅ Good
<div className="flex items-center justify-between p-4 bg-white rounded-lg shadow-md hover:shadow-lg transition">
<h2 className="text-xl font-bold text-gray-900">Title</h2>
</div>
// ❌ Bad - Inconsistent spacing and grouping
<div className="flex p-4 items-center bg-white justify-between rounded-lg shadow-md hover:shadow-lg transition">
<h2 className="font-bold text-xl text-gray-900">Title</h2>
</div>- Layout (flex, grid, display)
- Positioning (relative, absolute)
- Spacing (margin, padding)
- Sizing (width, height)
- Typography (font, text)
- Visual (background, border, shadow)
- Interactions (hover, focus, transition)
src/
├── components/
│ ├── common/ # Reusable components
│ ├── features/ # Feature-specific components
│ └── layout/ # Layout components
├── pages/ # Next.js pages
├── hooks/ # Custom React hooks
├── utils/ # Utility functions
├── types/ # TypeScript types/interfaces
├── constants/ # Constants and enums
└── styles/ # Global styles
- Components:
PascalCase.tsx(e.g.,PetCard.tsx) - Utilities:
camelCase.ts(e.g.,formatDate.ts) - Types:
PascalCase.tsorcamelCase.types.ts - Tests:
*.test.tsor*.spec.ts
// ✅ Good - Descriptive names
const petMedicalRecords = fetchRecords();
const isUserAuthenticated = checkAuth();
function calculateVaccinationDate(lastVaccination: Date): Date {
// implementation
}
// ❌ Bad - Unclear names
const data = fetchRecords();
const flag = checkAuth();
function calc(d: Date): Date {
// implementation
}// ✅ Good
const MAX_UPLOAD_SIZE = 5 * 1024 * 1024; // 5MB
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL;- Prefix with
is,has,should,can
// ✅ Good
const isLoading = true;
const hasPermission = false;
const shouldRender = true;
const canEdit = false;<type>(<scope>): <subject>
<body>
<footer>
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, etc.)refactor: Code refactoringtest: Adding or updating testschore: Maintenance tasks
# ✅ Good
feat(pet-records): add medical history timeline component
Implemented a timeline component to display pet medical records
in chronological order with filtering capabilities.
Closes #123
# ✅ Good
fix(auth): resolve token expiration issue
# ❌ Bad
update stuff// ✅ Good
try {
const data = await fetchPetData(petId);
return data;
} catch (error) {
console.error('Failed to fetch pet data:', error);
throw new Error('Unable to load pet information');
}
// ❌ Bad
try {
const data = await fetchPetData(petId);
return data;
} catch (error) {
// Silent failure
}// ✅ Good
async function loadPetData(petId: string): Promise<Pet> {
const pet = await fetchPet(petId);
const records = await fetchRecords(petId);
return { ...pet, records };
}
// ❌ Bad - Callback hell
function loadPetData(petId: string, callback: Function) {
fetchPet(petId, (pet) => {
fetchRecords(petId, (records) => {
callback({ ...pet, records });
});
});
}// ✅ Good - Organized imports
import { useState, useEffect } from 'react';
import Image from 'next/image';
import { fetchPetData } from '@/utils/api';
import { Pet } from '@/types/pet';
import Button from '@/components/common/Button';
// ❌ Bad - Unorganized
import Button from '@/components/common/Button';
import { useState, useEffect } from 'react';
import { Pet } from '@/types/pet';
import { fetchPetData } from '@/utils/api';
import Image from 'next/image';- React and Next.js imports
- Third-party libraries
- Internal utilities and types
- Components
- Styles
Before submitting a PR, ensure:
- Code follows the style guide
- All tests pass
- TypeScript has no errors
- ESLint has no warnings
- Code is properly formatted (Prettier)
- No console.logs in production code
- Proper error handling
- Meaningful variable names
- Comments for complex logic
- No hardcoded values (use constants)
Remember: Consistency is key. When in doubt, follow the existing patterns in the codebase.