Thank you for your interest in contributing to Vemetric! This document provides guidelines and instructions for you to get started.
- Contributor License Agreement
- Types of Contributions
- Local Development Setup
- Development Workflow
- Project Structure
- Testing
- Documentation
- Questions
If you want to contribute to Vemetric, you'll need to sign our Contributor License Agreement (CLA).
You'll be automatically prompted to sign it when creating your first pull request.
We welcome the following types of contributions:
- Submitting a fix / change
- Reporting a bug
- Proposing new features
- Discussing the current state of the code
You can take a look at our Issues on GitHub and see if there's something you'd like to tackle. If so, please add a comment that you start working on it and feel free to ask any questions.
In case you have ideas for contributing bigger changes to Vemetric, like a new feature, please first create an issue or discussion in our GitHub repository. We have a clear vision of how Vemetric should evolve and we don't want you to waste your time with things that don't align with it.
This section will help you set up Vemetric for local development.
Before you begin, ensure you have the following installed:
- Bun (v1.3.11 or higher) - JavaScript runtime and toolkit
- Docker and Docker Compose - For running local services
- Node.js (v20 or higher) - Required for some tooling
Follow these steps from the root directory to get Vemetric running locally:
# 1. Clone the repository
git clone https://github.com/vemetric/vemetric.git
cd vemetric
# 2. Install dependencies
bun install
# 3. Start Docker services for local Development (PostgreSQL, Redis, ClickHouse)
docker-compose up -d
# 4. Wait for services to be healthy (about 30 seconds)
docker-compose ps
# All services should show as "healthy"
# 5. Copy environment example files (see Environment Variables section below)
cp .env.example .env
# 6. Run PostgreSQL migrations
bun --filter database db:generate
bun --filter database db:deploy
# 7. Run ClickHouse migrations
bun --filter clickhouse migrate-local
# 8. Start the development servers
bun devBy default, Vemetric boots up a Proxy for local development that runs at port 4050. It ensures all services run under the same base domain with different subdomains.
Therefore, once everything is running, you can access:
- Web App & Backend: http://app.vemetric.localhost:4050
- Hub (Event Ingestion): http://hub.vemetric.localhost:4050
- API http://app.vemetric.localhost:4050/api
In case you want to have the Dev Proxy running on a different port, just specify VEMETRIC_DEV_PROXY_PORT in your .env file in the root of the monorepo.
Now that Vemetric is running, you should signup at http://app.vemetric.localhost:4050 to create an account.
Afterwards you'll be prompted to create an organization and a project (use vemetric.localhost:4050 as domain for the project). After creating a project, copy the token you'll see in the Dashboard of the newly created project.
Paste the token in the VEMETRIC_TOKEN variable of your .env file and restart the dev script with bun dev.
Now Vemetric will track itself and you should see data flowing in on your Dashboard while navigating around. Now you can test Vemetric and see local code changes being reflected in the application.
- Fork the repository - Create your own fork on GitHub
- Create a feature branch - Create a new branch for your feature/fix:
git checkout -b fix/description
- Make your changes - Write your code following our conventions
- Run tests - Ensure all tests pass:
bun run test - Lint your code - Check for linting issues:
bun lint
- Build the project - Ensure it builds without errors:
bun run build
- Commit your changes - Use clear, descriptive commit messages
- Push to your fork - Push your branch to GitHub
- Submit a pull request - Open a PR against the main repository
vemetric/
├── apps/ # Applications
│ ├── app/ # Vite SPA + Hono API server (single deployable service)
│ ├── hub/ # Event collection service
│ ├── worker/ # Background job processor
│ ├── bullboard/ # Queue monitoring dashboard
│ └── health-check/ # Service health monitoring
└── packages/ # Shared packages
├── common/ # Shared utilities, logic and types
├── database/ # PostgreSQL/Prisma models
├── clickhouse/ # ClickHouse client and schema
├── logger/ # Centralized logging
├── email/ # Email service
├── queues/ # Job queue abstractions
├── eslint-config/ # Shared ESLint config
└── tsconfig/ # TypeScript config presets
- Runtime: Bun (backend services)
- Frontend: React + TypeScript + Vite + Chakra UI v3
- Backend: Hono + tRPC + Better Auth
- Api: Hono + OpenAPI
- State Management: TanStack Query (tRPC) + Valtio
- Routing: TanStack Router
- Validation: Zod throughout the stack
- Queue System: BullMQ with Redis
- Logging: Pino with Axiom integration
- app: Vite SPA + Hono API server - Single deployable web app + API service
- hub: Bun + Hono - Event collection service (e.g.
/efor events,/ifor identification) - worker: Background job processor using BullMQ and Redis
- bullboard: Queue monitoring dashboard
- health-check: Service health monitoring, not needed for devlopment
Data Layer:
- PostgreSQL: User accounts, projects, organizations (via Prisma ORM)
- ClickHouse: High-volume analytics data (events, sessions, devices)
- Redis: Caching and job queues
# Run all tests
bun run test
# Run tests for specific package
bun --filter app test
# Run tests in watch mode
bun --filter app test:watchTests use Vitest and are located alongside source files:
src/
components/
Button.tsx
Button.test.tsx
- At the moment the Vemetric Docs are at an external repo and not publicly available
- Let us know which parts of the Vemetric Docs need to be changed in which way. We're working on making the source of the Vemetric Docs public as well to make this process easier.
- Keep inline documentation up to date
- Follow the existing documentation style
- Update the CLAUDE.md file when making significant architectural changes
- TypeScript: Use strict type checking throughout
- ESLint: All code must pass linting with 0 warnings
- Prettier: Format code before committing
- Naming: Use clear, descriptive names for variables, functions, and files
- Comments: Add comments for complex logic, but prefer self-documenting code
- File naming: Use kebab-case for file names (e.g.,
user-service.ts) - Component naming: Use PascalCase for React components
- Function naming: Use camelCase for functions and variables
- Constants: Use UPPER_SNAKE_CASE for constants
Feel free to open a new Discussion for any questions you might have.
For more architectural details, you can also take a look at the CLAUDE.md file.