Contributing to MarkPDFdown
January 26, 2026 ยท View on GitHub
Thank you for your interest in contributing to MarkPDFdown! This document provides guidelines and instructions for contributing to this project.
Table of Contents
- Code of Conduct
- How to Contribute
- Development Setup
- Development Workflow
- Code Style Guidelines
- Commit Guidelines
- Pull Request Process
- Getting Help
Code of Conduct
Our Pledge
We are committed to providing a welcoming and inspiring community for all. We expect all participants to:
- Be respectful: Treat everyone with respect. Engage in constructive criticism and avoid personal attacks.
- Be inclusive: Welcome newcomers and help them get started.
- Be collaborative: Work together to achieve the best outcomes for the project.
- Be professional: Maintain professional conduct in all interactions.
Unacceptable Behavior
- Harassment, discrimination, or offensive comments
- Trolling or personal/political attacks
- Publishing others' private information without permission
- Other conduct that could reasonably be considered inappropriate
How to Contribute
Reporting Bugs
If you find a bug, please create an issue with the following information:
- Description: A clear and concise description of the bug
- Steps to Reproduce: Detailed steps to reproduce the behavior
- Expected Behavior: What you expected to happen
- Actual Behavior: What actually happened
- Screenshots: If applicable, add screenshots
- Environment:
- OS: [e.g., Windows 11, macOS 14, Ubuntu 22.04]
- App Version: [e.g., 1.0.0]
- Node.js Version: [e.g., 18.17.0]
Suggesting Features
We welcome feature suggestions! Please create an issue with:
- Feature Description: Clear description of the proposed feature
- Use Case: Why this feature would be useful
- Proposed Solution: If you have ideas on how to implement it
- Alternatives Considered: Any alternative solutions you've considered
Code Contributions
- Fork the repository
- Create a feature branch from
master - Make your changes
- Write or update tests as needed
- Ensure all tests pass
- Submit a pull request
Development Setup
Prerequisites
- Node.js: v18+ recommended (ESM support required)
- npm: v8+ (comes with Node.js)
- Git: For version control
- Platform-specific tools:
- Windows: No additional tools needed
- macOS: Xcode Command Line Tools
- Linux: Standard build tools (
build-essentialon Debian/Ubuntu)
First-time Setup
# Clone repository
git clone <repository-url>
cd markpdfdown-desktop
# Install dependencies
npm install
# Generate Prisma client
npm run generate
# Run database migrations
npm run migrate:dev
# Start development server
npm run dev
Development Workflow
Adding New Features
Follow these steps when adding new features to the project:
1. Database Schema Changes
Create Prisma schema changes in src/core/infrastructure/db/schema.prisma:
# Run migrations in development
npm run migrate:dev
# Generate Prisma client
npm run generate
2. Create Repository
Add Repository in src/core/domain/repositories/:
// Example: src/core/domain/repositories/FeatureRepository.ts
import { prisma } from '../../infrastructure/db/index.js';
const featureRepository = {
findAll: () => prisma.feature.findMany(),
findById: (id: number) => prisma.feature.findUnique({ where: { id } }),
create: (data) => prisma.feature.create({ data }),
update: (id, data) => prisma.feature.update({ where: { id }, data }),
remove: (id) => prisma.feature.delete({ where: { id } }),
};
export default featureRepository;
3. Add Repository Tests
Add tests in src/core/domain/repositories/__tests__/:
// Example: FeatureRepository.test.ts
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { mockDeep, mockReset } from 'vitest-mock-extended'
import { PrismaClient } from '@prisma/client'
import featureRepository from '../FeatureRepository.js'
const prismaMock = mockDeep<PrismaClient>()
vi.mock('../../../infrastructure/db/index.js', () => ({ prisma: prismaMock }))
describe('featureRepository', () => {
beforeEach(() => { mockReset(prismaMock) })
it('should create feature', async () => {
prismaMock.feature.create.mockResolvedValue({ id: 1, name: 'test' })
const result = await featureRepository.create({ name: 'test' })
expect(result.id).toBe(1)
})
})
4. Add Application Services (if needed)
Add services in src/core/application/services/ and corresponding tests in src/core/application/services/__tests__/.
5. Create IPC Handler
Add IPC handler in src/main/ipc/handlers/feature.handler.ts:
import { ipcMain } from 'electron';
import featureRepository from '../../../core/domain/repositories/FeatureRepository.js';
export function registerFeatureHandlers() {
ipcMain.handle('feature:action', async (_, params) => {
try {
const result = await featureRepository.action(params);
return { success: true, data: result };
} catch (error: any) {
return { success: false, error: error.message };
}
});
console.log('[IPC] Feature handlers registered');
}
6. Register Handler
Register handler in src/main/ipc/handlers/index.ts.
7. Add IPC Handler Tests
Add tests in src/main/ipc/__tests__/handlers.test.ts:
it('should handle feature:action', async () => {
const mockData = { id: 1, name: 'test' }
vi.mocked(featureRepository.action).mockResolvedValue(mockData)
const result = await handlers.get('feature:action')!(null, params)
expect(result.success).toBe(true)
expect(result.data).toEqual(mockData)
})
8. Add Preload API
Add preload API in src/preload/index.ts:
feature: {
action: (params) => ipcRenderer.invoke('feature:action', params)
}
9. Update TypeScript Types
Update TypeScript types in src/renderer/electron.d.ts.
10. Update Frontend Components
Update React frontend components to use window.api.feature.action().
11. Add Component Tests (if new component)
Add tests in src/renderer/components/__tests__/:
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import FeatureComponent from '../FeatureComponent'
describe('FeatureComponent', () => {
it('should render and interact', async () => {
window.api.feature.action = vi.fn().mockResolvedValue({ success: true })
render(<FeatureComponent />)
const button = screen.getByRole('button')
await userEvent.click(button)
expect(window.api.feature.action).toHaveBeenCalled()
})
})
12. Add i18n Translations (if UI changes)
Add translations in src/renderer/locales/ for all supported languages.
13. Run Tests and Verification
# Run unit tests
npm run test:unit
# Run component tests (if applicable)
npm run test:renderer
# Check coverage
npm run test:coverage
# Run linting
npm run lint
# Type checking
npm run typecheck
# Test in development
npm run dev
Testing
This project uses Vitest as the test framework. For detailed testing documentation, see docs/TESTING_GUIDE.md.
# Run all tests
npm test
# Run unit tests (main/server)
npm run test:unit
# Run renderer tests (React components)
npm run test:renderer
# Watch mode (for development)
npm run test:watch
# Generate coverage report
npm run test:coverage
Code Style Guidelines
TypeScript
- Strict Mode: Enabled globally - no
anyunless explicitly allowed - Module System: ESM (
type: "module"in package.json) - Module Alias:
@alias available in frontend only- Backend uses relative imports with
.jsextensions
ESLint
- Config file:
eslint.config.js(flat config format) - Extends TypeScript-ESLint recommended config
- React hooks enforcement enabled
Naming Conventions
| Type | Convention | Example |
|---|---|---|
| Files (Controllers, DAL, Logic) | PascalCase | TaskController.ts, ProviderDal.ts |
| Variables/Functions | camelCase | createTasks, getAllTasks |
| Constants (config) | SCREAMING_SNAKE_CASE | MAX_RETRY_COUNT |
| Classes/Interfaces | PascalCase | Task, Provider |
| Database Models | PascalCase singular | Provider, Task, Model |
Commit Guidelines
This project follows Conventional Commits specification.
Commit Message Format
type(scope): description
scopeis optional- Description should be concise and descriptive
Commit Types
| Type | Description |
|---|---|
feat | A new feature |
fix | A bug fix |
docs | Documentation only changes |
style | Code style changes (formatting, etc.) |
refactor | Code change that neither fixes a bug nor adds a feature |
perf | Performance improvements |
test | Adding or updating tests |
chore | Maintenance tasks |
ci | CI/CD changes |
build | Build system changes |
revert | Revert a previous commit |
Examples
feat(auth): add login feature
fix(upload): resolve file size validation issue
docs: update README with new API examples
refactor(worker): simplify task processing logic
test(provider): add unit tests for provider repository
Pre-commit Checks
Always run before committing:
npm run lint
npm run typecheck
npm test
Pull Request Process
Before Submitting
-
Create a branch: Create a feature branch from
mastergit checkout -b feat/your-feature-name -
Make changes: Implement your changes following the code style guidelines
-
Test: Ensure all tests pass
npm test npm run lint npm run typecheck -
Commit: Follow the commit guidelines
Submitting a PR
- Push your branch to your fork
- Open a Pull Request against the
masterbranch - Fill in the PR template with:
- Description of changes
- Related issue numbers
- Screenshots (if applicable)
- Testing performed
PR Review Process
- At least one maintainer review is required
- All CI checks must pass
- Address any requested changes
- Once approved, the PR will be merged
After Merge
- Delete your feature branch
- Pull the latest
masterto your local repository
Getting Help
- Documentation: Check docs/ for detailed guides
- Issues: Search existing issues or create a new one
- Discussions: Use GitHub Discussions for questions
Thank you for contributing to MarkPDFdown!