Skip to main content

Welcome Contributors!

Thank you for your interest in contributing to Midday! This guide will help you get started with contributing to the project.
Midday is open source under the AGPL-3.0 license for non-commercial use. Commercial deployments require a commercial license.

Getting Started

1

Fork the Repository

Fork the repository on GitHub:
# Visit https://github.com/midday-ai/midday
# Click "Fork" button
2

Clone Your Fork

git clone https://github.com/YOUR_USERNAME/midday.git
cd midday
3

Install Bun

Midday requires Bun 1.3.10:
curl -fsSL https://bun.sh/install | bash

# Verify installation
bun --version
4

Install Dependencies

bun install
5

Set Up Environment

Create environment variables file:
cp .env.example .env.local
You’ll need:
  • Supabase project (database, auth, storage)
  • Banking provider credentials (optional for testing)
  • API keys for external services (optional)
6

Start Development

# Start all apps
bun dev

# Or start specific app
bun dev:dashboard  # http://localhost:3001
bun dev:api        # http://localhost:3003
bun dev:website    # http://localhost:3000

Development Workflow

Creating a Branch

Create a descriptive branch for your changes:
git checkout -b feature/add-export-csv
git checkout -b fix/transaction-sorting
git checkout -b docs/update-readme

Making Changes

  1. Find the right location
    • Apps: apps/dashboard, apps/api, etc.
    • Shared code: packages/
  2. Follow code style
    # Format code
    bun format
    
    # Lint
    bun lint
    
    # Type check
    bun typecheck
    
  3. Test your changes
    # Run tests
    bun test
    
    # Run specific tests
    cd packages/db
    bun test
    

Committing Changes

1

Stage Changes

git add .
2

Commit with Clear Message

Write clear, concise commit messages:
# Good commit messages
git commit -m "feat: add CSV export for transactions"
git commit -m "fix: resolve sorting issue in transaction list"
git commit -m "docs: update database setup guide"
git commit -m "refactor: simplify transaction matching logic"
Follow conventional commits format:
  • feat: - New feature
  • fix: - Bug fix
  • docs: - Documentation
  • style: - Code style changes
  • refactor: - Code refactoring
  • test: - Adding tests
  • chore: - Maintenance tasks
3

Push to Your Fork

git push origin feature/add-export-csv

Creating a Pull Request

1

Open PR on GitHub

  1. Go to https://github.com/midday-ai/midday
  2. Click “Pull Requests” → “New Pull Request”
  3. Select your fork and branch
2

Write Clear Description

Include:
## Description
Brief description of changes

## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update

## Testing
How to test these changes

## Screenshots (if applicable)
Before/after screenshots

## Checklist
- [ ] Code follows project style
- [ ] Tests pass
- [ ] Documentation updated
3

Wait for Review

  • CI checks will run automatically
  • Maintainers will review your PR
  • Address any feedback

Contribution Guidelines

Code Style

Formatting

  • Use Biome for formatting
  • 2 spaces for indentation
  • 80 character line width
  • Run bun format before committing

TypeScript

  • Use strict TypeScript
  • Define types for all functions
  • Avoid any types
  • Use Zod for runtime validation

React

  • Use functional components
  • Prefer hooks over classes
  • Keep components small and focused
  • Use React 19 features when appropriate

Naming

  • camelCase for variables/functions
  • PascalCase for components/types
  • UPPER_SNAKE_CASE for constants
  • Descriptive, meaningful names

Testing

Write tests for business logic:
packages/db/src/test/example.test.ts
import { describe, it, expect } from 'bun:test';
import { myFunction } from '../my-function';

describe('myFunction', () => {
  it('should return expected result', () => {
    const result = myFunction('input');
    expect(result).toBe('expected');
  });
  
  it('should handle edge cases', () => {
    expect(() => myFunction(null)).toThrow();
  });
});

Documentation

Good documentation helps everyone:
1

Code Comments

Add comments for complex logic:
/**
 * Matches receipts to transactions using AI embeddings
 * @param receiptId - ID of the receipt to match
 * @param threshold - Similarity threshold (0-1)
 * @returns Array of potential transaction matches
 */
export async function matchReceiptToTransactions(
  receiptId: string,
  threshold = 0.85
): Promise<TransactionMatch[]> {
  // Implementation...
}
2

README Updates

Update README files when adding features:
## Features

- Transaction tracking
- Receipt matching
- **NEW: CSV Export** - Export transactions to CSV
3

Inline Documentation

Document important patterns:
// IMPORTANT: Always include teamId in queries for RLS
const transactions = await db
  .select()
  .from(transactions)
  .where(eq(transactions.teamId, teamId));

Areas to Contribute

Bug Fixes

Find and fix bugs:
  • Check GitHub Issues
  • Test edge cases
  • Improve error handling

New Features

Add new functionality:
  • Enhance existing features
  • Add integrations
  • Improve UI/UX

Performance

Optimize performance:
  • Database query optimization
  • Frontend bundle size
  • API response times

Documentation

Improve docs:
  • Fix typos
  • Add examples
  • Write guides

Tests

Increase test coverage:
  • Write unit tests
  • Add integration tests
  • Test edge cases

Accessibility

Make Midday accessible:
  • Keyboard navigation
  • Screen reader support
  • ARIA labels

Security

Reporting Security Issues

DO NOT open public GitHub issues for security vulnerabilities.
Instead, email: [email protected]

Security Guidelines

When contributing:
1

Never Commit Secrets

  • No API keys, tokens, or passwords
  • Use environment variables
  • Add sensitive files to .gitignore
2

Validate User Input

import { z } from 'zod';

const schema = z.object({
  email: z.string().email(),
  amount: z.number().positive(),
});

const validated = schema.parse(input);
3

Use Parameterized Queries

Drizzle ORM handles this automatically:
// GOOD: Parameterized (safe)
await db
  .select()
  .from(users)
  .where(eq(users.email, userEmail));

// BAD: String concatenation (vulnerable to SQL injection)
await db.execute(sql`SELECT * FROM users WHERE email = '${userEmail}'`);
4

Implement RLS

All new tables must have Row Level Security policies:
CREATE POLICY "Users can only see their team's data"
  ON my_table
  FOR ALL
  USING (team_id IN (
    SELECT team_id FROM users_on_team WHERE user_id = auth.uid()
  ));

Out of Scope

Do not report:
  • Clickjacking on non-sensitive pages
  • Unauthenticated CSRF
  • Missing security headers (CSP, DNSSEC, CAA)
  • Email spoofing
  • DoS attacks
  • Social engineering

Communication

GitHub Issues

Report bugs and request features

GitHub Discussions

Ask questions and discuss ideas

Documentation

Read the full documentation

Website

Learn more about Midday

Code of Conduct

Our Standards

  • Be respectful - Treat everyone with respect
  • Be inclusive - Welcome diverse perspectives
  • Be constructive - Provide helpful feedback
  • Be patient - Maintainers are volunteers

Unacceptable Behavior

  • Harassment or discrimination
  • Trolling or insulting comments
  • Personal attacks
  • Publishing others’ private information

License

For non-commercial use:
  • Free to use and modify
  • Must open source modifications
  • Must maintain license
  • Cannot use for commercial purposes
By contributing, you agree that your contributions will be licensed under the same terms.

Recognition

Contributors are recognized in:
  • GitHub contributors list
  • Release notes
  • Public acknowledgment (if desired)
First-time contributors: Look for issues labeled good first issue to get started!

Next Steps

Architecture

Understand the system architecture

Database

Learn about the database schema

Monorepo

Master the monorepo structure

GitHub

Start contributing on GitHub

Thank you for contributing to Midday! Your contributions help make business management better for everyone.

Build docs developers (and LLMs) love