Contributing Guide - jra3/mulm GitHub Wiki
Thank you for your interest in contributing to the Mulm Breeder Awards Program platform! This guide will help you get started.
- Code of Conduct
- Getting Started
- Development Workflow
- Code Style Guidelines
- Testing Requirements
- Submitting Changes
- Review Process
We are committed to providing a welcoming and inclusive environment for all contributors, regardless of experience level.
Expected Behavior:
- โ Be respectful and constructive
- โ Focus on what's best for the project
- โ Accept constructive criticism gracefully
- โ Help newcomers get started
Unacceptable Behavior:
- โ Harassment or discriminatory comments
- โ Trolling or intentionally derailing discussions
- โ Publishing others' private information
Enforcement: Violations may result in temporary or permanent ban from the project.
Before contributing, ensure you have:
- Read the Development Setup guide
- Successfully run the application locally
- Reviewed the Project Overview
- Familiarized yourself with the codebase
For beginners:
- Look for issues labeled
good first issue - Documentation improvements
- Test coverage additions
- Bug fixes with clear reproduction steps
For experienced developers:
- Issues labeled
help wanted - Feature requests
- Performance improvements
- Security enhancements
Check with maintainers first for large features to ensure alignment with project direction.
# Fork the repository on GitHub
# Then clone your fork
git clone https://github.com/YOUR-USERNAME/mulm.git
cd mulm
# Add upstream remote
git remote add upstream https://github.com/jra3/mulm.git# Update main branch
git checkout main
git pull upstream main
# Create feature branch
git checkout -b feature/your-feature-name
# Or for bug fixes
git checkout -b fix/bug-descriptionBranch naming:
-
feature/- New features -
fix/- Bug fixes -
docs/- Documentation updates -
refactor/- Code refactoring -
test/- Test additions
# Start dev server
npm run dev
# Make changes
# Server hot-reloads automatically
# Run tests
npm test
# Run linter
npm run lintCommit message format:
type(scope): brief description
Longer explanation of what changed and why.
- Bullet points for details
- Multiple lines if needed
Fixes #123
Types:
-
feat- New feature -
fix- Bug fix -
docs- Documentation only -
style- Code style (formatting, no logic change) -
refactor- Code refactoring -
test- Adding or updating tests -
chore- Build process, dependencies
Examples:
git commit -m "feat(submissions): add photo upload support
Implements image upload functionality using Cloudflare R2 storage
with Sharp image processing for optimization.
- Adds /api/upload/image endpoint
- Processes images into 3 size variants
- Strips EXIF data for privacy
- Includes upload progress tracking via SSE
Fixes #45"git commit -m "fix(admin): correct witness confirmation button alignment
The confirm/decline buttons were misaligned on mobile. Updated
Tailwind classes to use flexbox layout.
Fixes #78"# Push your branch
git push origin feature/your-feature-name
# Create pull request on GitHub
# Fill out the PR templateStrict type checking enabled:
// โ
Good - explicit types
async function getMember(id: number): Promise<MemberRecord | null> {
return await query<MemberRecord>('SELECT * FROM members WHERE id = ?', [id]);
}
// โ Bad - implicit any
async function getMember(id) {
return await query('SELECT * FROM members WHERE id = ?', [id]);
}Use async/await (not callbacks):
// โ
Good
const results = await db.all('SELECT * FROM members');
// โ Bad
db.all('SELECT * FROM members', (err, results) => {
// Callback style - don't use
});Always finalize prepared statements:
// โ
Good
const stmt = await db.prepare('SELECT * FROM members WHERE id = ?');
try {
const result = await stmt.get(id);
return result;
} finally {
await stmt.finalize(); // Always finalize
}
// โ Bad - missing finalize (memory leak)
const stmt = await db.prepare('SELECT * FROM members WHERE id = ?');
return await stmt.get(id);CRITICAL Rules:
// โ
Good - double quotes, broken class chains
div(
class="bg-gradient-to-r from-yellow-50 to-amber-50" +
" rounded-lg shadow-lg p-6"
)
// โ Bad - single quotes, long chains
div(class='bg-gradient-to-r from-yellow-50 to-amber-50 rounded-lg shadow-lg p-6')Modifiers (hover:, md:, focus:):
// โ
Good - use class attribute
div(class="hover:bg-blue-500 md:flex focus:outline-none")
// โ Bad - dot notation with modifiers
div.hover:bg-blue-500.md:flexSimple utilities only with dot notation:
// โ
Good - simple utilities
div.flex.gap-4.items-center
// โ Bad - modifiers with dots
div.md:flex.hover:bg-blue-500SVG viewBox:
// โ
Good - lowercase
svg(viewbox="0 0 24 24")
// โ Bad - camelCase
svg(viewBox="0 0 24 24")See: CLAUDE.md - Pug Template Guidelines
Always use prepared statements:
// โ
Good - parameterized query
const results = await query<Member>(
'SELECT * FROM members WHERE contact_email = ?',
[email]
);
// โ Bad - string concatenation (SQL injection risk)
const results = await query<Member>(
`SELECT * FROM members WHERE contact_email = '${email}'`
);Use transactions for multiple writes:
// โ
Good - atomic operation
await withTransaction(async (db) => {
await db.run('INSERT INTO members ...');
await db.run('INSERT INTO submissions ...');
// Both succeed or both rollback
});
// โ Bad - separate operations (not atomic)
await db.run('INSERT INTO members ...');
await db.run('INSERT INTO submissions ...');# Check for issues
npm run lint
# Auto-fix where possible
npm run lint:fixKey rules:
- No unused variables
- Consistent quote style (single quotes for strings, double for JSX/templates)
- Semicolons required
- Proper async/await usage
New features:
- Unit tests for new utilities/functions
- Integration tests for database operations
- End-to-end tests for workflows
Bug fixes:
- Regression test demonstrating the bug
- Verification test showing fix works
Refactoring:
- Existing tests must still pass
- Add tests for edge cases if uncovered
// src/__tests__/myfeature.test.ts
import { describe, test, beforeEach, afterEach } from 'node:test';
import assert from 'node:assert';
import { setupTestDatabase } from './testDbHelper.helper';
describe('My Feature', () => {
let testDb;
beforeEach(async () => {
testDb = await setupTestDatabase();
});
afterEach(async () => {
await testDb.cleanup();
});
test('should do something specific', async () => {
// Arrange
const input = 'test data';
// Act
const result = await myFunction(input);
// Assert
assert.strictEqual(result, expectedValue);
});
});See: Testing Guide for comprehensive testing documentation.
# Run all tests
npm test
# Should see: All tests passed
# Run linter
npm run lint
# Should see: No errors foundPR will be rejected if:
- โ Tests are failing
- โ Linter shows errors
- โ New code has no tests
Before submitting a PR, ensure:
- Code follows style guidelines
- All tests pass (
npm test) - Linter passes (
npm run lint) - New tests added for new features/fixes
- Documentation updated (if needed)
- Commit messages follow format
- Branch is up to date with main
## Description
Brief description of what this PR does.
## Type of Change
- [ ] Bug fix (non-breaking change fixing an issue)
- [ ] New feature (non-breaking change adding functionality)
- [ ] Breaking change (fix or feature causing existing functionality to break)
- [ ] Documentation update
## Related Issues
Fixes #123
Related to #456
## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] Manual testing completed
## Screenshots (if applicable)
[Add screenshots of UI changes]
## Checklist
- [ ] Code follows project style guidelines
- [ ] Self-review completed
- [ ] Comments added for complex logic
- [ ] Documentation updated
- [ ] No new warnings generated
- [ ] Tests pass locallyโ Good PRs:
- Focused on single feature/fix
- Small and reviewable (< 500 lines)
- Clear description and test plan
- Screenshots for UI changes
- Commits are logical units
โ Bad PRs:
- Mix multiple unrelated changes
- Massive (1000+ lines)
- No description
- No tests
- Commits are random work-in-progress
If your PR is large:
- Break into smaller PRs
- Submit incrementally
- Each PR should be independently valuable
-
Automated Checks
- Tests run automatically via CI
- Linter runs automatically
- Must pass before review
-
Code Review
- Maintainer reviews within 1-3 days
- May request changes
- May ask questions for clarification
-
Revision
- Address review feedback
- Push new commits to same branch
- Re-request review when ready
-
Merge
- Maintainer merges when approved
- Your contribution is live!
Good responses:
- โ Ask clarifying questions
- โ Explain your reasoning
- โ Make requested changes promptly
- โ Thank reviewers for their time
Poor responses:
- โ Argue without listening
- โ Ignore feedback
- โ Take criticism personally
Remember: Code review is about the code, not about you personally. We're all working together to make the project better!
Always welcome:
- Fix typos or unclear explanations
- Add examples or diagrams
- Improve error messages
- Update outdated information
How to contribute docs:
- Edit wiki pages directly (if you have access)
- Or submit PR with documentation changes
- No tests required for doc-only changes
Before fixing:
- Check if issue already reported
- Reproduce the bug locally
- Write test demonstrating the bug
- Fix the bug
- Verify test now passes
Bug fix PR should include:
- Description of bug
- Steps to reproduce
- Root cause explanation
- Test proving fix works
Before implementing:
- Open issue describing the feature
- Discuss approach with maintainers
- Get approval before starting work
- Break large features into smaller PRs
Feature PR should include:
- Feature description and use case
- Design decisions explained
- Tests for happy path and edge cases
- Documentation updated
- Screenshots (for UI features)
Creating migrations:
- Follow Migration Guide
- Test with fresh database
- Test with existing data
- Document in PR what the migration does
Migration PR requirements:
- Migration follows naming convention:
NNN-description.sql - Includes both "-- Up" and "-- Down" sections
- Tested locally with fresh database
- Tested locally with existing data
- Comments explain purpose
Do NOT open public issues for security vulnerabilities.
Instead:
- Email [email protected] (or maintainer directly)
- Include detailed description
- Wait for response before disclosure
We will:
- Acknowledge within 48 hours
- Provide fix timeline
- Credit you in security advisory (if desired)
When contributing code:
โ DO:
- Use prepared statements for all SQL queries
- Validate all user input with Zod schemas
- Sanitize output (Pug does this automatically)
- Use HTTPS for external requests
- Hash passwords with scrypt (never plain text)
- Strip EXIF from uploaded images
โ DON'T:
- Concatenate user input into SQL
- Trust MIME types (validate magic bytes)
- Store secrets in code or environment variables
- Use MD5 or SHA1 for passwords
- Expose sensitive data in logs
See: Security Overview
Simplest contribution:
- Edit wiki page directly (if you have wiki access)
- Or fork repo, edit file, submit PR
- No tests needed for typo fixes
Example PR title: docs: fix typo in Member User Guide
Great first contribution:
- Find code with no tests or insufficient coverage
- Write test following Testing Guide
- Submit PR
Example PR title: test: add edge case tests for species search
Typical workflow:
- Reproduce: Verify bug exists
- Test: Write failing test
- Fix: Implement fix
- Verify: Test now passes
- Submit: Create PR
Example PR:
fix(submissions): handle null witness_verification_status
When witness field is null (old submissions), the status
display was throwing error. Added null check and default value.
Added test case for null witness status.
Fixes #123
More involved:
- Discuss: Open issue or discussion
- Design: Plan database changes, API, UI
- Implement: Write code incrementally
- Test: Add comprehensive tests
- Document: Update relevant docs
- Review: Address feedback
- Merge: Celebrate! ๐
โ Good example - Single focused change:
feat(admin): add bulk approve submissions button
Adds button to approval queue allowing admins to approve
multiple submissions at once.
- Added checkbox to each submission row
- Added "Approve Selected" button
- Backend endpoint handles bulk approvals in transaction
- Email notifications sent for each approval
Changes:
- src/routes/admin.ts: bulk approve handler
- src/views/admin/queue.pug: checkboxes and button
- src/__tests__/admin.test.ts: bulk approval tests
Files changed: 3
Lines added: 156
โ Bad example - Multiple unrelated changes:
fix: various fixes
Fixed some bugs and added some features.
Files changed: 23
Lines added: 2,431
โ Good titles:
feat(api): add member search endpoint with fuzzy matchingfix(submissions): resolve race condition in witness confirmationdocs(wiki): add troubleshooting guide for common errors
โ Bad titles:
updatefixeschanges to admin stuff
Include:
- What: What changed
- Why: Why the change was needed
- How: How it was implemented (for complex changes)
- Testing: How you tested it
- Screenshots: For UI changes
Provide constructive feedback:
โ Good:
This looks great! One suggestion: could we extract this logic
into a separate function for reusability?
Also, should we add a test case for the empty array scenario?
โ Bad:
This code is terrible. Rewrite it.
Focus on:
- Correctness
- Security
- Performance
- Maintainability
- Test coverage
Be nice! Contributors are volunteering their time.
Respond professionally:
โ Good:
Thanks for the feedback! I'll extract that into a helper function.
Good catch on the empty array case - adding that test now.
โ Bad:
No, my way is better.
Don't take it personally! Reviews make the code better.
For maintainers:
- Merge approved PRs to main
- Update version in package.json (semantic versioning)
- Create git tag:
git tag v1.2.3 - Push tag:
git push origin v1.2.3 - Deploy to production
- Monitor for issues
Semantic versioning:
-
1.0.0โ1.0.1- Bug fixes (patch) -
1.0.0โ1.1.0- New features (minor) -
1.0.0โ2.0.0- Breaking changes (major)
Before asking:
- Search existing issues and discussions
- Read relevant documentation
- Try to solve it yourself first
Where to ask:
- GitHub Discussions - General questions, ideas
- GitHub Issues - Bug reports, feature requests
- Pull Request Comments - Questions about specific code
How to ask good questions:
- Context: What are you trying to do?
- Problem: What's not working?
- Attempts: What have you tried?
- Environment: Dev or production? Node version?
- Code: Relevant code snippets or error messages
Example good question:
I'm trying to add a new field to the submission form, but when I submit
the form, the field value isn't being saved to the database.
Steps I've taken:
1. Added field to Pug template: input(name="new_field" type="text")
2. Added field to Zod schema: new_field: z.string()
3. Ran tests - they pass
Environment: Node 20.5, local development
Error: No error shown, but when I query the database, the new_field
column is NULL.
Am I missing a step in the form submission handler?
All contributors will be:
- Listed in GitHub contributors
- Mentioned in release notes (for significant contributions)
- Credited in commit history
Not just code! We appreciate:
- ๐ Documentation improvements
- ๐ Bug reports
- ๐ก Feature suggestions
- ๐งช Test additions
- ๐จ UI/UX improvements
- ๐ Code reviews
- โ Answering questions in discussions
Every contribution matters!
- Development Setup - Set up your local environment
- Testing Guide - How to write tests
- Database Schema - Database structure
- Migration Guide - Creating migrations
- CLAUDE.md - Comprehensive project documentation
Thank you for contributing to the Mulm project. Your efforts help aquarium societies worldwide manage their breeding programs and preserve species through captive propagation.
Happy coding! ๐๐ฑ๐ชธ