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.tsx → EventCard.tsx
  • Utilities: camelCase.ts → formatDate.ts
  • Constants: kebab-case.ts → competition-types.ts
  • Tests: *.test.ts → formatDate.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!