Thank you for your interest in contributing to Meshtastic Node Mapper! This document provides guidelines and instructions for contributing to the project.
We are committed to providing a welcoming and inclusive environment for all contributors. Please be respectful, constructive, and professional in all interactions.
Before creating a bug report:
- Check the existing issues to avoid duplicates
- Verify the bug exists in the latest version
- Collect relevant information (logs, screenshots, steps to reproduce)
Bug Report Template:
**Describe the bug**
A clear description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. See error
**Expected behavior**
What you expected to happen.
**Screenshots**
If applicable, add screenshots.
**Environment:**
- OS: [e.g. Ubuntu 22.04]
- Docker version: [e.g. 20.10.21]
- Browser: [e.g. Chrome 120]
- Version: [e.g. 1.0.0]
**Additional context**
Any other relevant information.We welcome feature suggestions! Before creating a feature request:
- Check if the feature already exists or is planned
- Consider if it fits the project's scope and goals
- Think about how it would benefit users
Feature Request Template:
**Is your feature request related to a problem?**
A clear description of the problem.
**Describe the solution you'd like**
A clear description of what you want to happen.
**Describe alternatives you've considered**
Other solutions or features you've considered.
**Additional context**
Mockups, examples, or other relevant information.-
Fork the repository
# Click "Fork" on GitHub, then clone your fork git clone https://github.com/YOUR_USERNAME/meshtastic-node-mapper.git cd meshtastic-node-mapper
-
Set up development environment
# Install dependencies npm install cd backend && npm install cd ../frontend && npm install cd .. # Start development services docker compose -f docker-compose.dev.yml up -d
-
Create a feature branch
git checkout -b feature/your-feature-name # or git checkout -b fix/your-bug-fix
-
Make your changes
- Write clean, readable code
- Follow the project's code style
- Add tests for new features
- Update documentation as needed
-
Test your changes
# Run linting npm run lint # Run tests npm test # Run integration tests npm run test:integration # Check test coverage npm run test:coverage
-
Commit your changes
# Stage your changes git add . # Commit with a descriptive message git commit -m "feat: add new feature description"
-
Push to your fork
git push origin feature/your-feature-name
-
Create a Pull Request
- Go to the original repository on GitHub
- Click "New Pull Request"
- Select your fork and branch
- Fill out the PR template
- Submit the pull request
Before submitting:
- Code follows the project's style guidelines
- All tests pass
- New features have tests
- Documentation is updated
- Commit messages follow conventions
- No merge conflicts with main branch
PR Description should include:
- What changes were made and why
- How to test the changes
- Screenshots (for UI changes)
- Related issue numbers (e.g., "Closes #123")
PR Review Process:
- Automated checks run (linting, tests, build)
- Maintainers review the code
- Feedback is provided if changes are needed
- Once approved, PR is merged
General Rules:
- Use TypeScript for all new code
- Follow ESLint configuration
- Use meaningful variable and function names
- Add JSDoc comments for public APIs
- Keep functions small and focused
Example:
/**
* Retrieves active nodes from the database
* @param filters - Optional filters to apply
* @returns Promise resolving to array of nodes
*/
async function getActiveNodes(filters?: NodeFilters): Promise<Node[]> {
const nodes = await nodeRepository.findActive(filters);
return nodes.filter(node => node.isOnline);
}Naming Conventions:
- Variables/Functions: camelCase (
getUserData,nodeCount) - Classes/Interfaces: PascalCase (
NodeService,IRepository) - Constants: UPPER_SNAKE_CASE (
MAX_RETRIES,API_URL) - Files: kebab-case (
node-service.ts,api-client.ts)
Component Structure:
import React from 'react';
import { ComponentProps } from './types';
import './Component.css';
/**
* Component description
*/
export const Component: React.FC<ComponentProps> = ({ prop1, prop2 }) => {
// Hooks at the top
const [state, setState] = useState<string>('');
// Event handlers
const handleClick = (): void => {
// Handler logic
};
// Render
return (
<div className="component">
{/* JSX */}
</div>
);
};Best Practices:
- Use functional components with hooks
- Extract complex logic into custom hooks
- Memoize expensive computations
- Use TypeScript for props and state
- Keep components focused and reusable
Conventions:
- Use CSS modules or styled-components
- Follow BEM naming for CSS classes
- Use CSS variables for theming
- Mobile-first responsive design
Example:
.node-card {
/* Layout */
display: flex;
flex-direction: column;
/* Spacing */
padding: var(--spacing-md);
margin-bottom: var(--spacing-sm);
/* Visual */
background-color: var(--color-surface);
border-radius: var(--border-radius);
}
.node-card__title {
font-size: var(--font-size-lg);
font-weight: var(--font-weight-bold);
}We follow the Conventional Commits specification.
Format:
<type>(<scope>): <description>
[optional body]
[optional footer]
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, semicolons, etc.)refactor: Code refactoring without changing functionalityperf: Performance improvementstest: Adding or updating testschore: Maintenance tasks, dependency updatesci: CI/CD changesbuild: Build system changes
Scope (optional):
api: Backend API changesui: Frontend UI changesdb: Database changesmqtt: MQTT integration changesdocs: Documentation changes
Examples:
feat(api): add node filtering by hardware type
fix(ui): resolve map marker clustering issue
docs: update installation guide with Docker Compose v2
test(api): add integration tests for MQTT service
refactor(db): optimize node query performance
chore: update dependencies to latest versions
Breaking Changes:
feat(api)!: change node API response format
BREAKING CHANGE: Node API now returns `nodeId` instead of `id`
What to test:
- Individual functions and methods
- Component rendering and behavior
- Edge cases and error handling
- Business logic
Example:
describe('NodeService', () => {
describe('getActiveNodes', () => {
it('should return only online nodes', async () => {
// Arrange
const mockNodes = [
{ id: '1', isOnline: true },
{ id: '2', isOnline: false }
];
jest.spyOn(nodeRepository, 'findAll').mockResolvedValue(mockNodes);
// Act
const result = await nodeService.getActiveNodes();
// Assert
expect(result).toHaveLength(1);
expect(result[0].id).toBe('1');
});
});
});What to test:
- API endpoints end-to-end
- Database operations
- External service integrations
- Multi-component interactions
Example:
describe('GET /api/v1/nodes', () => {
it('should return all nodes', async () => {
// Arrange
await createTestNodes(3);
// Act
const response = await request(app)
.get('/api/v1/nodes')
.expect(200);
// Assert
expect(response.body.data).toHaveLength(3);
});
});What to test:
- System properties that should always hold
- Input validation across many cases
- Data consistency
Example:
import fc from 'fast-check';
describe('Node validation', () => {
it('should validate any valid node structure', () => {
fc.assert(fc.property(
fc.record({
nodeId: fc.string({ minLength: 1 }),
shortName: fc.string({ maxLength: 4 }),
isOnline: fc.boolean()
}),
(node) => {
const result = validateNode(node);
expect(result.isValid).toBe(true);
}
));
});
});Minimum Requirements:
- Unit Tests: 80% coverage
- Integration Tests: Critical paths covered
- Property Tests: Key invariants tested
Running Coverage:
npm run test:coverageJSDoc for Functions:
/**
* Calculates the distance between two geographic points
* @param point1 - First point with latitude and longitude
* @param point2 - Second point with latitude and longitude
* @returns Distance in kilometers
* @throws {Error} If coordinates are invalid
* @example
* const distance = calculateDistance(
* { lat: 40.7128, lng: -74.0060 },
* { lat: 34.0522, lng: -118.2437 }
* );
*/
function calculateDistance(point1: Point, point2: Point): number {
// Implementation
}README Files:
- Every major directory should have a README
- Explain the purpose and structure
- Provide usage examples
- Link to related documentation
When adding features, update:
- User Guide: How to use the feature
- API Guide: New endpoints or changes
- Installation Guide: New requirements
- Troubleshooting: Common issues
After submitting a PR:
- Automated checks run (CI/CD)
- Maintainers review within 1-3 days
- Address feedback promptly
- Request re-review when ready
- PR is merged when approved
Responding to Feedback:
- Be open to suggestions
- Ask questions if unclear
- Make requested changes
- Update the PR description if scope changes
Review Checklist:
- Code follows style guidelines
- Tests are adequate and passing
- Documentation is updated
- No security vulnerabilities
- Performance impact is acceptable
- Breaking changes are documented
- Commit messages follow conventions
Providing Feedback:
- Be constructive and respectful
- Explain the reasoning behind suggestions
- Distinguish between required changes and suggestions
- Approve when ready or request changes
We follow Semantic Versioning:
- Major (1.0.0): Breaking changes
- Minor (0.1.0): New features, backwards compatible
- Patch (0.0.1): Bug fixes, backwards compatible
- Update version in
package.json - Update CHANGELOG.md
- Create release branch
- Run full test suite
- Build and test Docker images
- Create GitHub release
- Tag the release
- Deploy to production
- Documentation: Check the docs directory
- Issues: Search existing issues
- Discussions: Ask in GitHub Discussions
- Discord: Join our community server (if available)
Good Questions Include:
- What you're trying to accomplish
- What you've already tried
- Relevant code snippets or error messages
- Your environment details
Example:
I'm trying to add a new API endpoint for exporting telemetry data.
I've created the route and controller, but I'm not sure how to
implement pagination for large datasets. I've looked at the nodes
endpoint but it uses a different approach. What's the recommended
pattern for paginating time-series data?
Environment: Node.js 18, PostgreSQL 15, TimescaleDB
Contributors are recognized in:
- GitHub contributors list
- CONTRIBUTORS.md file
- Release notes
- Project README
Thank you for contributing to Meshtastic Node Mapper! 🎉
Questions? Open a discussion or reach out to the maintainers.