Thank you for your interest in contributing to MarkPDFdown! This document provides guidelines and instructions for contributing to this project.
- Code of Conduct
- How to Contribute
- Development Setup
- Development Workflow
- Code Style Guidelines
- Commit Guidelines
- Pull Request Process
- Getting Help
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.
- Harassment, discrimination, or offensive comments
- Trolling or personal/political attacks
- Publishing others' private information without permission
- Other conduct that could reasonably be considered inappropriate
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]
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
- 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
- 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)
# 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 devFollow these steps when adding new features to the project:
Create Prisma schema changes in src/core/infrastructure/db/schema.prisma:
# Run migrations in development
npm run migrate:dev
# Generate Prisma client
npm run generateAdd 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;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)
})
})Add services in src/core/application/services/ and corresponding tests in src/core/application/services/__tests__/.
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');
}Register handler in src/main/ipc/handlers/index.ts.
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)
})Add preload API in src/preload/index.ts:
feature: {
action: (params) => ipcRenderer.invoke('feature:action', params)
}Update TypeScript types in src/renderer/electron.d.ts.
Update React frontend components to use window.api.feature.action().
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()
})
})Add translations in src/renderer/locales/ for all supported languages.
# 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 devThis 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- 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
- Config file:
eslint.config.js(flat config format) - Extends TypeScript-ESLint recommended config
- React hooks enforcement enabled
| 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 |
This project follows Conventional Commits specification.
type(scope): description
scopeis optional- Description should be concise and descriptive
| 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 |
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 repositoryAlways run before committing:
npm run lint
npm run typecheck
npm test-
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
- 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
- At least one maintainer review is required
- All CI checks must pass
- Address any requested changes
- Once approved, the PR will be merged
- Delete your feature branch
- Pull the latest
masterto your local repository
- 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!