Skip to content

Latest commit

Β 

History

History
450 lines (364 loc) Β· 12.7 KB

File metadata and controls

450 lines (364 loc) Β· 12.7 KB

🀝 Contributing Guidelines

Thank you for your interest in contributing to OpenLN! We welcome contributions from developers of all skill levels and backgrounds. This guide will help you get started and ensure a smooth contribution process.

🌟 Ways to Contribute

Code Contributions

  • Bug Fixes: Help us squash bugs and improve stability
  • New Features: Add exciting new functionality
  • Performance Improvements: Optimize existing code
  • Documentation: Improve or expand documentation
  • Tests: Add or improve test coverage

Non-Code Contributions

  • Bug Reports: Report issues you encounter
  • Feature Requests: Suggest new features or improvements
  • Design: UI/UX design improvements
  • Community Support: Help other contributors in discussions
  • Translation: Localization and internationalization

πŸš€ Getting Started

1. Set Up Your Development Environment

Follow our Development Setup Guide to get your local environment ready.

2. Find an Issue to Work On

3. Claim an Issue

  • Comment on the issue saying you'd like to work on it
  • Wait for a maintainer to assign it to you
  • If you're a first-time contributor, start with smaller issues

πŸ“‹ Contribution Process

1. Fork and Clone

# Fork the repository on GitHub
# Then clone your fork
git clone https://github.com/YOUR_USERNAME/Openln-Engine.git
cd Openln-Engine

# Add upstream remote
git remote add upstream https://github.com/Openln-git/Openln-Engine.git

2. Create a Feature Branch

# Create and switch to a new branch
git checkout -b feature/your-feature-name

# Or for bug fixes
git checkout -b fix/bug-description

3. Make Your Changes

  • Write clean, readable code
  • Follow our Code Style Guide
  • Add tests for new functionality
  • Update documentation as needed

4. Test Your Changes

# Run tests for both client and server
cd client && npm test
cd ../server && npm test

# Run linting
cd client && npm run lint
cd ../server && npm run lint

# Test the application manually
npm run dev

5. Commit Your Changes

# Add your changes
git add .

# Commit with a descriptive message
git commit -m "feat: add user profile customization feature"

6. Push and Create Pull Request

# Push to your fork
git push origin feature/your-feature-name

# Create a pull request on GitHub
# Fill out the PR template completely

πŸ“ Pull Request Guidelines

PR Title Format

Use conventional commit format:

  • feat: for new features
  • fix: for bug fixes
  • docs: for documentation changes
  • style: for formatting changes
  • refactor: for code refactoring
  • test: for adding tests
  • chore: for maintenance tasks

PR Description Template

## Description
Brief description of the changes made.

## Type of Change
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update

## How Has This Been Tested?
Describe the tests that you ran to verify your changes.

## Screenshots (if applicable)
Add screenshots to help explain your changes.

## Checklist
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes

PR Review Process

  1. Automated Checks: All CI checks must pass
  2. Code Review: At least one maintainer review required
  3. Testing: Manual testing by reviewers if needed
  4. Approval: Maintainer approval before merge
  5. Merge: Squash and merge into main branch

πŸ“ Code Standards

General Principles

  • DRY (Don't Repeat Yourself): Avoid code duplication
  • KISS (Keep It Simple, Stupid): Prefer simple solutions
  • YAGNI (You Aren't Gonna Need It): Don't over-engineer
  • Clean Code: Write self-documenting code

JavaScript/TypeScript Standards

// Use descriptive variable names
const userProfileData = getUserProfile();

// Use async/await over promises
async function fetchUserData(userId) {
  try {
    const response = await api.get(`/users/${userId}`);
    return response.data;
  } catch (error) {
    logger.error('Failed to fetch user data:', error);
    throw error;
  }
}

// Use TypeScript interfaces
interface User {
  id: string;
  email: string;
  profile: UserProfile;
}

React Component Standards

// Use functional components with hooks
import React, { useState, useEffect } from 'react';

interface UserCardProps {
  userId: string;
  onUserClick: (user: User) => void;
}

export const UserCard: React.FC<UserCardProps> = ({ userId, onUserClick }) => {
  const [user, setUser] = useState<User | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchUser = async () => {
      try {
        const userData = await getUserById(userId);
        setUser(userData);
      } catch (error) {
        console.error('Error fetching user:', error);
      } finally {
        setLoading(false);
      }
    };

    fetchUser();
  }, [userId]);

  if (loading) return <LoadingSpinner />;
  if (!user) return <ErrorMessage message="User not found" />;

  return (
    <div className="user-card" onClick={() => onUserClick(user)}>
      <img src={user.avatar} alt={`${user.name}'s avatar`} />
      <h3>{user.name}</h3>
      <p>{user.email}</p>
    </div>
  );
};

API Development Standards

// RESTful route structure
router.get('/api/v1/users', getUsersController);
router.get('/api/v1/users/:id', getUserByIdController);
router.post('/api/v1/users', createUserController);
router.put('/api/v1/users/:id', updateUserController);
router.delete('/api/v1/users/:id', deleteUserController);

// Controller function structure
export const getUserByIdController = async (req, res, next) => {
  try {
    const { id } = req.params;
    
    // Validate input
    if (!mongoose.isValidObjectId(id)) {
      return res.status(400).json({
        success: false,
        message: 'Invalid user ID format'
      });
    }

    const user = await User.findById(id).select('-password');
    
    if (!user) {
      return res.status(404).json({
        success: false,
        message: 'User not found'
      });
    }

    res.status(200).json({
      success: true,
      data: user
    });
  } catch (error) {
    next(error);
  }
};

πŸ§ͺ Testing Guidelines

Writing Tests

  • Write tests for all new functionality
  • Maintain or improve existing test coverage
  • Use descriptive test names
  • Follow the AAA pattern (Arrange, Act, Assert)

Frontend Testing

// Component testing with React Testing Library
import { render, screen, fireEvent } from '@testing-library/react';
import { UserCard } from './UserCard';

describe('UserCard', () => {
  const mockUser = {
    id: '1',
    name: 'John Doe',
    email: 'john@example.com',
    avatar: 'avatar.jpg'
  };

  it('should display user information correctly', () => {
    render(<UserCard user={mockUser} onUserClick={jest.fn()} />);
    
    expect(screen.getByText('John Doe')).toBeInTheDocument();
    expect(screen.getByText('john@example.com')).toBeInTheDocument();
    expect(screen.getByAltText("John Doe's avatar")).toBeInTheDocument();
  });

  it('should call onUserClick when card is clicked', () => {
    const mockOnClick = jest.fn();
    render(<UserCard user={mockUser} onUserClick={mockOnClick} />);
    
    fireEvent.click(screen.getByRole('button'));
    expect(mockOnClick).toHaveBeenCalledWith(mockUser);
  });
});

Backend Testing

// API endpoint testing with Jest and Supertest
import request from 'supertest';
import app from '../app';
import User from '../models/User';

describe('GET /api/v1/users/:id', () => {
  beforeEach(async () => {
    await User.deleteMany({});
  });

  it('should return user when valid ID is provided', async () => {
    const user = await User.create({
      name: 'Test User',
      email: 'test@example.com',
      password: 'hashedpassword'
    });

    const response = await request(app)
      .get(`/api/v1/users/${user._id}`)
      .expect(200);

    expect(response.body.success).toBe(true);
    expect(response.body.data.name).toBe('Test User');
    expect(response.body.data.password).toBeUndefined();
  });

  it('should return 404 when user not found', async () => {
    const nonExistentId = new mongoose.Types.ObjectId();
    
    const response = await request(app)
      .get(`/api/v1/users/${nonExistentId}`)
      .expect(404);

    expect(response.body.success).toBe(false);
    expect(response.body.message).toBe('User not found');
  });
});

πŸ“š Documentation Guidelines

Code Documentation

  • Use JSDoc for function documentation
  • Add inline comments for complex logic
  • Update README files when needed
  • Document API endpoints

JSDoc Example

/**
 * Calculates the user's learning progress based on completed modules
 * @param {string} userId - The unique identifier for the user
 * @param {string} courseId - The unique identifier for the course
 * @returns {Promise<number>} The progress percentage (0-100)
 * @throws {Error} When user or course is not found
 */
async function calculateLearningProgress(userId, courseId) {
  // Implementation here
}

πŸ› Issue Reporting

Bug Reports

When reporting bugs, please include:

  • Clear title: Describe the issue concisely
  • Steps to reproduce: Detailed steps to recreate the bug
  • Expected behavior: What should happen
  • Actual behavior: What actually happens
  • Environment: OS, browser, Node.js version
  • Screenshots: If applicable
  • Error messages: Full error messages and stack traces

Feature Requests

For feature requests, include:

  • Problem description: What problem does this solve?
  • Proposed solution: How should it work?
  • Alternatives: Other solutions you've considered
  • Use cases: Real-world examples
  • Priority: How important is this feature?

🏷️ Labels and Tags

Issue Labels

  • bug: Something isn't working
  • enhancement: New feature or request
  • good first issue: Good for newcomers
  • help wanted: Extra attention is needed
  • documentation: Improvements or additions to documentation
  • question: Further information is requested
  • wontfix: This will not be worked on

Priority Labels

  • priority: high: Critical issues that need immediate attention
  • priority: medium: Important issues for next release
  • priority: low: Nice to have improvements

πŸŽ‰ Recognition

Contributors

We appreciate all contributors! Contributors are recognized in:

  • GitHub contributors list
  • Release notes
  • Project documentation
  • Community highlights

Becoming a Maintainer

Active contributors who demonstrate:

  • Consistent high-quality contributions
  • Good understanding of the codebase
  • Helpful community interaction
  • Reliable code review skills

May be invited to become maintainers with additional privileges.

πŸ“ž Getting Help

Communication Channels

  • GitHub Issues: Bug reports and feature requests
  • GitHub Discussions: General questions and ideas
  • Code Reviews: Specific code-related questions

Response Times

  • Issues: We aim to respond within 48 hours
  • Pull Requests: Initial review within 72 hours
  • Questions: Response within 24 hours during weekdays

πŸ“œ Code of Conduct

Our Standards

  • Be respectful: Treat everyone with respect and kindness
  • Be inclusive: Welcome people of all backgrounds and experience levels
  • Be constructive: Provide helpful feedback and suggestions
  • Be patient: Remember that everyone is learning

Unacceptable Behavior

  • Harassment or discrimination of any kind
  • Trolling, insulting, or derogatory comments
  • Publishing private information without permission
  • Any conduct that would be inappropriate in a professional setting

Enforcement

Violations of the code of conduct may result in:

  1. Warning
  2. Temporary ban from contributions
  3. Permanent ban from the project

Report violations to the maintainers via email or private message.


Thank you for contributing to OpenLN! Your efforts help make education more accessible and personalized for everyone. πŸš€