Bỏ qua

Contributing Guidelines

Welcome to the Football Booking Backend project! This guide will help you get started with contributing.

Table of Contents

Getting Started

Prerequisites

  • Node.js 20+
  • npm 9+
  • Docker & Docker Compose
  • Git

Installation

  1. Clone the repository:
git clone <repository-url>
cd football-booking-backend
  1. Install dependencies:
npm install
  1. Setup Git hooks:
npm run prepare
  1. Install recommended VS Code extensions (if using VS Code):
  2. Open VS Code
  3. Press Cmd+Shift+P (Mac) or Ctrl+Shift+P (Windows/Linux)
  4. Type "Show Recommended Extensions"
  5. Install all recommended extensions

First Time Setup

Run the code quality setup script:

chmod +x scripts/setup-code-quality.sh
./scripts/setup-code-quality.sh

Development Workflow

1. Create a Branch

Always create a new branch for your work:

git checkout -b <type>/<scope>/<short-description>

Branch naming conventions:

  • feat/booking/add-conflict-detection
  • fix/payment/stripe-webhook-timeout
  • refactor/user/extract-keycloak-sync
  • docs/readme/update-setup-instructions
  • test/field/add-search-integration-tests
  • chore/deps/update-nestjs

2. Make Changes

  • Write clean, self-documenting code
  • Add comments for complex logic
  • Follow the code standards (see below)
  • Write tests for new features
  • Update documentation if needed

3. Before Committing

Run these commands to ensure code quality:

# Format code
npm run format

# Fix linting issues
npm run lint:fix

# Run type checking
npm run typecheck

# Run tests
npm test

Or run all checks at once:

npm run check:all

4. Commit Your Changes

We use Conventional Commits:

git commit -m "feat(booking): add double booking prevention

- Add distributed lock with Redis
- Implement conflict detection service
- Add integration tests

Closes #123"

Commit message format:

<type>(<scope>): <subject>

<body>

<footer>

Types:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation changes
  • style: Code style changes (formatting, missing semi-colons, etc.)
  • refactor: Code refactoring
  • perf: Performance improvements
  • test: Adding or updating tests
  • chore: Maintenance tasks
  • ci: CI/CD changes
  • build: Build system changes

Scopes:

  • Service names: api-gateway, user-service, field-service, booking-service, payment-service, notification-service
  • Library names: shared, database, messaging, cache, observability
  • Other: docker, ci, deps, config

5. Push and Create PR

git push origin <your-branch-name>

Then create a Pull Request on GitHub.

Code Standards

TypeScript

Type Safety

DO: Use explicit types

function calculateTotal(price: number, quantity: number): number {
  return price * quantity;
}

DON'T: Use any

function calculateTotal(price: any, quantity: any) {
  // ❌ Avoid any
  return price * quantity;
}

Null Safety

DO: Handle null/undefined cases

function getUserName(user?: User): string {
  return user?.name ?? 'Anonymous';
}

DON'T: Assume values exist

function getUserName(user: User): string {
  return user.name; // ❌ May crash if user is undefined
}

Async/Await

DO: Always await promises

async function getUser(id: string): Promise<User> {
  return await this.userRepository.findById(id);
}

DON'T: Forget to await

async function getUser(id: string) {
  return this.userRepository.findById(id); // ❌ Returns Promise<Promise<User>>
}

Naming Conventions

Type Convention Example
Files kebab-case user-service.ts
Classes PascalCase UserService
Interfaces PascalCase (no I prefix) User (not IUser)
Type Aliases PascalCase UserId
Enums PascalCase UserRole
Enum Members UPPER_CASE ADMIN, CUSTOMER
Variables camelCase userName
Constants UPPER_SNAKE_CASE MAX_RETRY_COUNT
Functions camelCase calculateTotal
Methods camelCase findById

Import Organization

Imports should be organized in this order:

  1. Node.js built-in modules
  2. External dependencies
  3. Internal packages (@football-booking/*)
  4. Relative imports (parent/sibling)
  5. Type imports

Example:

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';

import { KafkaProducerService } from '@football-booking/messaging';
import { CacheService } from '@football-booking/cache';

import { BookingRepository } from './booking.repository';
import { CreateBookingDto } from './dto/create-booking.dto';

import type { Booking } from './entities/booking.entity';

This is enforced automatically by ESLint and Prettier.

Documentation

Add JSDoc comments for:

  • All public classes
  • All public methods
  • Complex functions
  • All interfaces and type aliases

Example:

/**
 * Service for managing football field bookings
 */
@Injectable()
export class BookingService {
  /**
   * Creates a new booking with conflict detection
   *
   * @param userId - The ID of the user making the booking
   * @param createDto - Booking details
   * @returns The created booking
   * @throws ConflictException if time slot is already booked
   */
  async create(userId: string, createDto: CreateBookingDto): Promise<Booking> {
    // Implementation
  }
}

Error Handling

DO: Use specific exception types

if (!field) {
  throw new NotFoundException(`Field ${id} not found`);
}

DON'T: Use generic errors

if (!field) {
  throw new Error('Field not found'); // ❌ Too generic
}

Logging

DO: Use appropriate log levels

this.logger.log('Booking created successfully', { bookingId });
this.logger.warn('Payment timeout, will retry', { paymentId });
this.logger.error('Failed to send notification', error);

DON'T: Use console.log (will fail pre-commit hook)

console.log('Debug info'); // ❌ Will be rejected

Testing

Unit Tests

Write unit tests for:

  • Services (business logic)
  • Utilities
  • Complex functions

Example:

describe('BookingService', () => {
  it('should create a booking', async () => {
    const result = await service.create(userId, createDto);
    expect(result).toBeDefined();
    expect(result.status).toBe(BookingStatus.PENDING);
  });

  it('should throw ConflictException for double booking', async () => {
    await expect(service.create(userId, createDto)).rejects.toThrow(ConflictException);
  });
});

Integration Tests

Write integration tests for:

  • Controllers (API endpoints)
  • Database operations
  • External service integrations

Running Tests

# Run all tests
npm test

# Run tests for a specific service
nx test booking-service

# Run tests with coverage
npm run test:cov

# Run tests in watch mode
npm run test:watch

Pull Request Process

Before Creating PR

  1. ✅ All tests pass
  2. ✅ Code is formatted (npm run format)
  3. ✅ No linting errors (npm run lint)
  4. ✅ No TypeScript errors (npm run typecheck)
  5. ✅ Added tests for new features
  6. ✅ Updated documentation

PR Title

Use the same format as commit messages:

feat(booking): add conflict detection for double booking

PR Description Template

## Description

Brief description of changes

## Type of Change

- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update

## Changes Made

- Change 1
- Change 2

## Testing

- [ ] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] Manual testing completed

## Screenshots (if applicable)

## Checklist

- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Comments added for complex code
- [ ] Documentation updated
- [ ] No new warnings
- [ ] Tests pass locally

Code Review Guidelines

As a reviewer:

  • Be respectful and constructive
  • Ask questions to understand intent
  • Suggest improvements, don't demand
  • Approve if changes meet standards

As an author:

  • Respond to all comments
  • Ask for clarification if needed
  • Make requested changes or explain why not
  • Thank reviewers for their time

Commit Message Guidelines

Examples of Good Commits

Good:

feat(booking): add conflict detection for double booking

- Implement distributed lock using Redis
- Add conflict detection service
- Add integration tests
- Update booking controller

Closes #123

Good:

fix(payment): handle Stripe webhook timeout

The webhook handler was timing out for large payments.
Added timeout configuration and retry logic.

Fixes #456

Good:

docs(readme): update installation instructions

- Add Docker prerequisite
- Update environment variables section
- Fix broken links

Examples of Bad Commits

Bad:

Update stuff

Problem: Too vague, no type, no scope

Bad:

feat: new feature

Problem: No scope, unclear what feature

Bad:

Fix bug.

Problem: Has period at end, no scope, too vague

Bad:

This is a really long commit message that exceeds the maximum allowed length of one hundred characters

Problem: Exceeds 100 character limit

Questions?

If you have questions about contributing, please:

  1. Check existing documentation
  2. Search closed issues/PRs
  3. Ask in team chat
  4. Create a discussion on GitHub

Thank you for contributing! 🎉