Thank you for your interest in contributing! This document provides guidelines and instructions for contributing to the project.
We are committed to providing a welcoming and inspiring community for all. We pledge to make participation in our project a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
- Use welcoming and inclusive language
- Be respectful of differing viewpoints and experiences
- Gracefully accept constructive criticism
- Focus on what is best for the community
- Show empathy towards other community members
Before creating bug reports, please check the existing issues to avoid duplicates. When you create a bug report, include as many details as possible:
Bug Report Template:
**Describe the bug**
A clear description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '...'
3. See error
**Expected behavior**
What you expected to happen.
**Screenshots**
If applicable, add screenshots.
**Environment:**
- OS: [e.g., Ubuntu 22.04]
- Browser: [e.g., Chrome 120]
- Version: [e.g., 1.0.0]
**Additional context**
Any other context about the problem.Feature suggestions are welcome! Please create an issue with the following:
Feature Request Template:
**Is your feature request related to a problem?**
A clear description of the problem.
**Describe the solution you'd like**
What you want to happen.
**Describe alternatives you've considered**
Other solutions you've thought about.
**Use case**
Who would benefit and how?
**Additional context**
Mockups, examples, etc.IMPORTANT: The main branch is protected. All changes MUST go through a branch and pull request.
-
Create a feature branch from
main:git checkout main git pull origin main git checkout -b feature/your-feature-name # or: fix/bug-description, docs/update-readme, etc. -
Make your changes following our coding standards
-
Add tests if applicable
-
Update documentation if needed
-
Ensure tests pass:
npm test -
Commit your changes with clear messages (see format below)
-
Push to your branch:
git push origin feature/your-feature-name
-
Create a Pull Request on GitHub:
- Target the
mainbranch - Fill out the PR template
- Request review from maintainers
- Address any review comments
- Target the
-
After approval, a maintainer will merge your PR
Use descriptive branch names with prefixes:
feature/- New features (e.g.,feature/bulk-transaction-import)fix/- Bug fixes (e.g.,fix/donation-webhook-signature)docs/- Documentation updates (e.g.,docs/update-deployment-guide)refactor/- Code refactoring (e.g.,refactor/account-tree-component)test/- Test additions/updates (e.g.,test/add-accounting-tests)chore/- Maintenance tasks (e.g.,chore/update-dependencies)
- Keep changes focused - one feature/fix per PR
- Write clear commit messages (see below)
- Update relevant documentation
- Add tests for new features
- Ensure all tests pass
- Follow the existing code style
- Link related issues in PR description
We follow Conventional Commits:
<type>(<scope>): <subject>
<body>
<footer>
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, etc.)refactor: Code refactoringtest: Adding or updating testschore: Maintenance tasks
Examples:
feat(transactions): add bulk transaction import
Allow organization admins to import multiple transactions
from CSV files, matching against chart of accounts.
Closes #123
fix(donations): correct Stripe webhook signature verification
The webhook was failing in production due to incorrect
signature validation. Now properly validates signatures.
Fixes #456
- Node.js 18+
- PostgreSQL 14+
- Git
-
Clone your fork:
git clone https://github.com/YOUR_USERNAME/transparency.git cd transparency -
Install dependencies:
npm install
-
Set up environment:
cp .env.example .env.local # Edit .env.local with your credentials -
Set up database:
npx prisma generate npx prisma db push npx prisma db seed
-
Start development server:
npm run dev
- Use TypeScript for all code
- Avoid
anytypes - use proper typing - Use interfaces for object shapes
- Use enums for fixed sets of values
Good:
interface Transaction {
id: string;
amount: number;
date: Date;
}
function createTransaction(data: Transaction): Promise<Transaction> {
// ...
}Bad:
function createTransaction(data: any): any {
// ...
}ALWAYS use the correct import path for PrismaClient:
// ✅ CORRECT - Use this
import { PrismaClient } from '@/generated/prisma/client';
import { Organization, Account, UserRole } from '@/generated/prisma/client';
import { prisma } from '@/lib/prisma';
// ❌ WRONG - Will break Vercel builds
import { PrismaClient } from '@/generated/prisma';
import { PrismaClient } from '@prisma/client';Why: Our Prisma schema uses a custom output directory (output = "../src/generated/prisma"), so imports must include the /client suffix. Using the wrong path will cause TypeScript compilation errors in Vercel deployments.
Before committing Prisma-related changes:
- Verify the import path is correct
- Run
npm run type-check - Run
npm run buildto ensure it compiles - Check existing code for the correct pattern
See COPILOT_GUIDELINES.md for more details.
- Use functional components with hooks
- Keep components small and focused
- Use TypeScript props interfaces
- Extract reusable logic into custom hooks
Good:
interface TransactionCardProps {
transaction: Transaction;
onEdit: (id: string) => void;
}
export function TransactionCard({ transaction, onEdit }: TransactionCardProps) {
return (
<Card>
<CardHeader>{transaction.description}</CardHeader>
<CardContent>${transaction.amount}</CardContent>
</Card>
);
}- One component per file
- Co-locate related files
- Use index files for cleaner imports
- Keep files under 300 lines
- Components: PascalCase (
TransactionList.tsx) - Files: kebab-case for utilities (
format-currency.ts) - Variables: camelCase (
totalAmount) - Constants: UPPER_CASE (
MAX_TRANSACTIONS) - Types/Interfaces: PascalCase (
TransactionType)
- Use Tailwind utility classes
- Create reusable components with Shadcn/ui
- Avoid inline styles
- Use CSS modules for complex custom styles
- Use proper HTTP methods (GET, POST, PUT, DELETE)
- Return consistent response formats
- Include proper error handling
- Validate input with Zod
Example:
// app/api/transactions/route.ts
import { NextResponse } from 'next/server';
import { z } from 'zod';
const schema = z.object({
amount: z.number().positive(),
description: z.string().min(1),
});
export async function POST(req: Request) {
try {
const body = await req.json();
const data = schema.parse(body);
const transaction = await createTransaction(data);
return NextResponse.json(transaction);
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: 'Invalid input', details: error.errors },
{ status: 400 }
);
}
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}# Run all tests
npm test
# Run tests in watch mode
npm test:watch
# Run E2E tests
npm test:e2e
# Run type checking
npm run type-check
# Run linting
npm run lint- Write tests for new features
- Aim for >80% code coverage
- Test edge cases and error conditions
- Use descriptive test names
Example:
import { describe, it, expect } from 'vitest';
import { calculateAccountBalance } from './accounting';
describe('calculateAccountBalance', () => {
it('should calculate asset account balance correctly', () => {
const transactions = [
{ debit: 100, credit: 0 },
{ debit: 50, credit: 30 },
];
const balance = calculateAccountBalance('ASSET', transactions);
expect(balance).toBe(120);
});
it('should handle empty transactions', () => {
const balance = calculateAccountBalance('ASSET', []);
expect(balance).toBe(0);
});
});-
Update schema:
// prisma/schema.prisma model NewModel { id String @id @default(uuid()) // ... fields }
-
Create migration:
npx prisma migrate dev --name add_new_model
-
Update seed data if needed:
// prisma/seed.ts await prisma.newModel.create({ ... });
- Keep migrations small and focused
- Test migrations on a copy of production data
- Include rollback strategy
- Document breaking changes
- Comment complex logic
- Use JSDoc for public functions
- Explain why, not what
Good:
/**
* Calculates account balance using double-entry bookkeeping rules.
* Asset and expense accounts: debits increase, credits decrease.
* Liability, equity, and revenue: credits increase, debits decrease.
*/
function calculateBalance(account: Account): number {
// ...
}- Keep README.md up to date
- Add examples for new features
- Update setup instructions if needed
- Document all API endpoints
- Include request/response examples
- Note authentication requirements
DO NOT create public issues for security vulnerabilities. Email security@radbooks.org instead.
- Never commit secrets or credentials
- Use environment variables
- Validate and sanitize all inputs
- Use parameterized queries (Prisma does this)
- Implement rate limiting on sensitive endpoints
- Keep dependencies updated
- Optimize database queries
- Use pagination for large lists
- Implement caching where appropriate
- Lazy load components
- Optimize images (use Next.js Image)
# Lighthouse CI
npm run lighthouse
# Bundle analysis
npm run analyze- Update version in
package.json - Update CHANGELOG.md
- Create release branch:
release/v1.2.0 - Run full test suite
- Create pull request to
main - After merge, create git tag:
v1.2.0 - Deploy to production
- Discord: Join our community
- GitHub Discussions: Ask questions
- Email: dev@radbooks.org
Contributors will be recognized in:
- CONTRIBUTORS.md file
- Release notes
- Project website
Thank you for contributing to financial transparency! 🎉