Contributing to JSON Resume
July 16, 2026 ยท View on GitHub
Thank you for your interest in contributing to JSON Resume! This document provides guidelines and instructions for contributing to the project.
๐ Table of Contents
- Code of Conduct
- Getting Started
- Development Setup
- Project Structure
- Code Standards
- Testing
- Pull Request Process
- Commit Message Guidelines
- Contributing Themes
Code of Conduct
This project focuses exclusively on technical excellence. We expect all contributors to:
- Be professional and respectful
- Focus on code quality and technical merit
- Provide constructive feedback in code reviews
- Follow the established coding standards
Getting Started
-
Fork the repository on GitHub
-
Clone your fork locally:
git clone https://github.com/YOUR_USERNAME/jsonresume.org.git cd jsonresume.org -
Add upstream remote:
git remote add upstream https://github.com/jsonresume/jsonresume.org.git -
Create a feature branch:
git checkout -b feature/your-feature-name
Development Setup
Prerequisites
- Node.js 18+ (LTS recommended)
- pnpm 8.15.9+
- Git
- Supabase CLI (for database operations)
Installation
-
Install dependencies:
pnpm install -
Set up environment variables:
# Copy the example file cp apps/registry/.env.example apps/registry/.env # Edit .env and add your credentials # See .env.example for required variables -
Generate Prisma client:
pnpm --filter registry db:generate -
Start development server:
pnpm devThis starts:
- Registry app: http://localhost:3000
- Homepage: http://localhost:3001 (if applicable)
Supabase Setup
The registry app uses Supabase for data storage.
Database name: registry
# Link to your Supabase project
supabase link --project-ref your-project-ref
# Pull latest schema
supabase db pull
# Run migrations (if any)
supabase db push
Project Structure
jsonresume.org/
โโโ apps/
โ โโโ homepage/ # Marketing site
โ โโโ homepage2/ # New marketing site
โ โโโ registry/ # Main resume registry app
โโโ packages/
โ โโโ resume-core/ # Framework-agnostic theme primitives
โ โโโ ats-validator/ # ATS compatibility validation
โ โโโ themes/ # Resume theme implementations
โ โ โโโ jsonresume-theme-reference/
โ โ โโโ jsonresume-theme-modern/
โ โ โโโ jsonresume-theme-standard/
โ โ โโโ ... (13+ themes)
โ โโโ ui/ # Shared UI components
โ โโโ eslint-config/ # Shared ESLint config
โโโ scripts/ # Utility scripts
Code Standards
File Size Limit
CRITICAL: All files must be โค150 lines. No exceptions.
If a file exceeds 150 lines:
- Extract business logic into hooks (
useFeatureName.ts) - Split UI into sub-components
- Move utilities to helper files
- Follow the structure in
CLAUDE.md
Code Organization
feature/
โโโ index.ts # Public API exports
โโโ FeatureComponent.tsx # Main component (<150 lines)
โโโ useFeatureLogic.ts # Business logic hook
โโโ FeatureHelpers.ts # Pure utility functions
โโโ FeatureTypes.ts # TypeScript types
โโโ __tests__/ # Tests
โโโ FeatureComponent.test.tsx
โโโ useFeatureLogic.test.ts
TypeScript
- Use TypeScript for all new code
- Avoid
any- use proper types orunknown - Export types for public APIs
- Use strict mode
Styling
- Use Tailwind CSS for styling
- Follow existing component patterns
- Mobile-first responsive design
- Dark mode support where applicable
AI/LLM Integration
IMPORTANT: Always use Vercel AI SDK v5 (ai package):
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
const { text } = await generateText({
model: openai('gpt-4o-mini', {
apiKey: process.env.OPENAI_API_KEY,
}),
prompt: 'Your prompt here',
});
โ DO NOT use OpenAI SDK directly for chat completions โ DO use Vercel AI SDK for unified API across providers
Testing
Running Tests
# Run all tests
pnpm test
# Run tests for specific package
pnpm --filter registry test
# Run E2E tests
pnpm test:e2e
Test Requirements
- Unit tests: >80% coverage for utilities and logic
- Component tests: >70% coverage for UI components
- Integration tests: All API routes must have tests
- E2E tests: Critical user flows (login, create resume, export)
Writing Tests
// Component test example
import { render, screen } from '@testing-library/react';
import { FeatureComponent } from './FeatureComponent';
describe('FeatureComponent', () => {
it('renders correctly', () => {
render(<FeatureComponent />);
expect(screen.getByText('Expected Text')).toBeInTheDocument();
});
});
Pull Request Process
Before Submitting
-
Update your branch:
git fetch upstream git rebase upstream/master -
Run quality checks:
pnpm lint # ESLint pnpm prettier # Format check pnpm test # All tests pnpm build # Build check -
Verify file sizes:
# Check if any files exceed 150 lines find . -name "*.ts" -o -name "*.tsx" -o -name "*.js" | xargs wc -l | awk '\$1 > 150'
PR Requirements
โ Required:
- All tests passing
- No ESLint errors
- Code formatted with Prettier
- All files โค150 lines
- Test coverage maintained/improved
- No new security vulnerabilities (
pnpm audit) - Documentation updated (if needed)
PR Description Template
## Description
[Clear description of changes]
## Related Issues
Closes #123, Relates to #456
## Changes Made
- [ ] Feature/fix 1
- [ ] Feature/fix 2
## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] E2E tests added/updated
- [ ] Manual testing completed
## Performance Impact
[Any performance implications]
## Breaking Changes
[Any breaking changes]
## Screenshots/Demos
[If UI changes]
Review Process
- Automated checks must pass (CI/CD)
- Code review by maintainer(s)
- Address feedback and update PR
- Squash and merge once approved
Commit Message Guidelines
We use Conventional Commits:
<type>(<scope>): <subject>
[optional body]
[optional footer]
Types
feat: New featurefix: Bug fixdocs: Documentation onlystyle: Code style (formatting, semicolons, etc.)refactor: Code refactoringperf: Performance improvementtest: Adding/updating testschore: Maintenance tasksci: CI/CD changes
Examples
feat(api): add cover letter generation endpoint
Implements AI-powered cover letter generation using Vercel AI SDK v5.
Uses GPT-4o-mini for content generation.
Closes #123
fix(auth): resolve GitHub OAuth redirect issue
The callback URL was incorrectly configured for production environment.
Updated to use dynamic URL based on deployment context.
Fixes #456
Contributing Themes
Want to add your resume theme to the registry? Here's everything you need to know.
Quick Start: Using @jsonresume/core Components (Recommended)
The fastest way to build a new theme is using our composable component library:
// index.js
import {
Section,
SectionTitle,
ListItem,
DateRange,
BadgeList,
} from '@jsonresume/core';
export function render(resume) {
const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>${resume.basics.name}</title>
<link rel="stylesheet" href="https://unpkg.com/@jsonresume/core@0.3.1/src/styles/tokens.css">
<style>
body {
font-family: var(--resume-font-sans);
max-width: var(--resume-max-width);
margin: 0 auto;
padding: 40px 20px;
}
</style>
</head>
<body>
${Section({
children: `
<h1>${resume.basics.name}</h1>
<p>${resume.basics.label}</p>
`,
})}
${Section({
children: `
${SectionTitle({ text: 'Work Experience' })}
${resume.work
.map(
(job) => `
${ListItem({
title: job.position,
subtitle: job.company,
date: DateRange({
startDate: job.startDate,
endDate: job.endDate,
}),
description: job.summary,
})}
`
)
.join('')}
`,
})}
${Section({
children: `
${SectionTitle({ text: 'Skills' })}
${resume.skills
.map(
(skill) => `
<div>
<strong>${skill.name}</strong>
${BadgeList({ items: skill.keywords })}
</div>
`
)
.join('')}
`,
})}
</body>
</html>
`;
return html;
}
Benefits:
- โ ATS-friendly by default - semantic HTML, standard fonts
- โ 10x faster development - no need to write HTML from scratch
- โ Tested components - all primitives have unit tests
- โ Design tokens - consistent styling with CSS variables
- โ Framework-agnostic - works with any setup
Available Components:
Section()- Wrapper for resume sectionsSectionTitle()- Styled section headingsListItem()- Experience/education entriesDateRange()- Start/end date displayBadge()/BadgeList()- Skills, keywords, tags
See Working Examples:
packages/themes/jsonresume-theme-reference/- Complete implementationpackages/themes/jsonresume-theme-modern/- Card-based modern designpackages/resume-core/README.md- Full API documentation
Theme Requirements
CRITICAL: Themes must be serverless-compatible. The registry runs on Vercel's serverless functions, which means:
โ Cannot use:
fs.readFileSync()or any filesystem operationsfs.readFile(),fs.readdirSync(), etc.__dirnameor__filenamefor file paths- Dynamic file loading at runtime
โ Must use:
- ES6 imports for templates and styles
- Build-time bundling (Vite, webpack, rollup)
- All assets inlined at compile time
- OR @jsonresume/core components (recommended)
Quick Start: Converting Your Theme
Before (โ Breaks on Vercel)
// index.js
const fs = require('fs');
const Handlebars = require('handlebars');
function render(resume) {
const template = fs.readFileSync(__dirname + '/template.hbs', 'utf-8');
const css = fs.readFileSync(__dirname + '/style.css', 'utf-8');
return Handlebars.compile(template)({
css: `<style>${css}</style>`,
resume,
});
}
module.exports = { render };
After (โ Works on Vercel)
// index.js
import Handlebars from 'handlebars';
import template from './template.hbs?raw'; // Vite raw import
import css from './style.css?inline'; // Vite inline import
export function render(resume) {
return Handlebars.compile(template)({
css: `<style>${css}</style>`,
resume,
});
}
Step-by-Step Migration Guide
Option 1: Use Vite (Recommended)
-
Install Vite and plugins:
npm install --save-dev vite vite-plugin-handlebars -
Create
vite.config.js:import { defineConfig } from 'vite'; export default defineConfig({ build: { lib: { entry: './index.js', formats: ['cjs'], fileName: 'index', }, rollupOptions: { external: ['handlebars'], }, }, }); -
Update imports to use Vite's special imports:
import template from './template.hbs?raw'; import css from './style.css?inline'; -
Add build script to
package.json:{ "scripts": { "build": "vite build", "prepublishOnly": "npm run build" }, "main": "./dist/index.cjs" } -
Build and test:
npm run build npm publish
Option 2: Inline Everything Manually
For simple themes, you can inline content directly:
// index.js
import Handlebars from 'handlebars';
const template = `
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; }
/* your styles here */
</style>
</head>
<body>
<h1>{{resume.basics.name}}</h1>
<!-- your template here -->
</body>
</html>
`;
export function render(resume) {
return Handlebars.compile(template)({ resume });
}
Testing Your Theme Locally
-
Install your theme in the registry:
cd jsonresume.org pnpm --filter registry add your-theme-name -
Add it to
themeConfig.js:// apps/registry/lib/formatters/template/themeConfig.js export const THEMES = { // ... existing themes 'your-theme': require('your-theme-name'), }; -
Start the dev server:
pnpm dev -
Test your theme:
http://localhost:3000/thomasdavis?theme=your-theme
Working Examples
Check these themes in the repo for reference:
- @jsonresume/core components:
packages/themes/jsonresume-theme-reference(complete example) - @jsonresume/core with custom styles:
packages/themes/jsonresume-theme-modern(card-based design) - Simple approach:
packages/themes/jsonresume-theme-standard - Vite bundling:
packages/themes/jsonresume-theme-professional - Handlebars templates:
packages/themes/jsonresume-theme-spartacus
Common Issues
Issue: "Cannot find module"
Cause: Vite isn't bundling your files
Fix: Ensure you're using ?raw or ?inline suffixes for non-JS imports
Issue: "Template is undefined"
Cause: Import path is incorrect
Fix: Use relative paths (./template.hbs) not absolute paths
Issue: Theme works locally but fails on Vercel
Cause: Still using fs somewhere
Fix: Search your code for require('fs') or fs.readFile
Submitting Your Theme
Once your theme is serverless-compatible:
- Publish to npm (if not already published)
- Open an issue at #36
- Provide:
- Theme name
- npm package name
- Link to repository
- Confirmation that it doesn't use
fsoperations
We'll review and add it to the registry!
Need Help?
- Examples: See
packages/directory in this repo - Questions: Comment on issue #36
- Stuck: We're happy to help! Just ask.
Getting Help
- Documentation: Check README.md and CLAUDE.md
- Issues: Search existing issues or create a new one
- Discussions: Ask questions in GitHub Discussions
- Security: See SECURITY.md for reporting vulnerabilities
Additional Resources
Thank you for contributing to JSON Resume! ๐