Skip to main content

Contribution Guide

Thank you for your interest in contributing to CheerKeeper! This guide explains how to get involved.

Getting Started

  1. Set up your local environment
  2. Familiarize yourself with the architecture
  3. Review the database schema

Types of Contributions

Bug Fixes

Found a bug? We appreciate fixes for:

  • UI/UX issues
  • Data handling errors
  • Performance problems
  • Mobile app crashes

Features

Have an idea? Consider:

  • Is this something event organizers need?
  • Does it help parents find their kids' performances?
  • Is it simple enough for all user skill levels?

Documentation

Help improve our docs:

  • Fix typos and unclear sections
  • Add examples and screenshots
  • Translate to other languages

Development Workflow

1. Create a Branch

git checkout -b feature/your-feature-name
# or
git checkout -b fix/issue-description

2. Make Changes

  • Write clean, readable code
  • Follow existing patterns
  • Add tests for new functionality
  • Update documentation as needed

3. Test Locally

# Admin
npm run lint
npm run typecheck
npm run test

# Mobile
npx expo start --clear

4. Commit

Write clear commit messages:

# Good
git commit -m "Add session filtering to schedule view"
git commit -m "Fix notification timing on Android"

# Avoid
git commit -m "Fix stuff"
git commit -m "WIP"

5. Open a Pull Request

  • Describe what changed and why
  • Link related issues
  • Include screenshots for UI changes
  • Request review from maintainers

Code Style

TypeScript

// Use explicit types
function getEvent(id: string): Promise<Event> {
// ...
}

// Prefer interfaces for objects
interface EventInput {
name: string;
startDate: Date;
location?: Location;
}

// Use const for immutable values
const MAX_PERFORMANCES = 500;

React Components

// Functional components with typed props
interface ButtonProps {
label: string;
onClick: () => void;
variant?: 'primary' | 'secondary';
}

export function Button({ label, onClick, variant = 'primary' }: ButtonProps) {
return (
<button
className={`btn btn-${variant}`}
onClick={onClick}
>
{label}
</button>
);
}

File Naming

  • Components: PascalCase.tsxEventCard.tsx
  • Utilities: camelCase.tsformatDate.ts
  • Constants: kebab-case.tscompetition-types.ts
  • Tests: *.test.tsformatDate.test.ts

Project Conventions

API Routes

// app/api/events/route.ts

export async function GET(request: Request) {
const session = await getUnifiedSession();
if (!session) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}

try {
const events = await prisma.event.findMany({
where: { companyId: session.companyId },
});
return Response.json({ data: events });
} catch (error) {
return Response.json({ error: 'Internal error' }, { status: 500 });
}
}

Database Queries

// Use Prisma's type-safe queries
const event = await prisma.event.findUnique({
where: { id: eventId },
include: {
sessions: true,
eventUnits: {
orderBy: { performanceTime: 'asc' },
},
},
});

Error Handling

// Throw typed errors
throw new SessionNotFoundError(sessionId);

// Return appropriate HTTP codes
return Response.json(
{ error: { code: 'SESSION_NOT_FOUND', message: 'Session not found' } },
{ status: 409 }
);

Testing

Unit Tests

import { calculateCascade } from './cascade';

describe('calculateCascade', () => {
it('shifts performances after changed time', () => {
const performances = [
{ id: '1', time: '09:00' },
{ id: '2', time: '09:08' },
];

const result = calculateCascade(performances, '1', 15);

expect(result[0].time).toBe('09:15');
expect(result[1].time).toBe('09:23');
});
});

Integration Tests

describe('POST /api/events', () => {
it('creates an event', async () => {
const response = await fetch('/api/events', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
body: JSON.stringify({ name: 'Test Event' }),
});

expect(response.status).toBe(201);
const data = await response.json();
expect(data.name).toBe('Test Event');
});
});

Documentation

When adding features, update:

  • JSDoc comments for functions
  • README if setup changes
  • This docs site for user-facing features

Doc Style

  • Use simple language
  • Include code examples
  • Add screenshots for UI features
  • Link to related docs

Review Process

  1. Automated checks run on PR
  2. Maintainer review for code quality
  3. Testing in staging environment
  4. Merge after approval

Need Help?

Recognition

Contributors are recognized in:

  • Release notes
  • Contributors list
  • Annual thank-you post

Thank you for helping make CheerKeeper better for the cheer and dance community!