Thank you for your interest in contributing! This document provides guidelines for setting up your development environment, writing code, running tests, and submitting pull requests.
- Getting Started
- Development Setup
- Running Tests
- Code Style and Linting
- Database Migrations
- Git Workflow
- Pull Request Guidelines
- Commit Message Conventions
- Node.js 20.9.0 or higher
- Docker and Docker Compose (for running Redis and PostgreSQL locally)
- Git
git clone https://github.com/SmartDropLabs/smartdrop-backend.git
cd smartdrop-backendThe fastest way to set up a complete development environment with Redis and PostgreSQL:
# Start all services (API, Redis, PostgreSQL)
docker-compose up
# In another terminal, install dependencies
npm installThe API will be available at http://localhost:4000. Hot-reload is enabled via Docker volumes.
Services:
- API:
http://localhost:4000 - Redis:
localhost:6379 - PostgreSQL:
localhost:5432(user:smartdrop, password:smartdrop)
If you prefer to run services locally:
# Install dependencies
npm install
# Start Redis (in a separate terminal)
redis-server
# Start PostgreSQL (or use a managed service)
# Set DATABASE_URL environment variable
# Run the development server
npm run devCreate a .env file based on .env.example:
cp .env.example .envEdit .env and set:
PORT=4000REDIS_HOST=localhost(or your Redis host)DATABASE_URL=postgres://user:password@localhost:5432/smartdrop- API keys for CoinGecko and CoinMarketCap (optional for development)
See .env.example for a complete list. Key variables:
NODE_ENV: Set totestwhen running testsREDIS_HOST,REDIS_PORT: Redis connectionDATABASE_URL: PostgreSQL connection stringCOINGECKO_API_KEY: Optional; used for price oracleCOINMARKETCAP_API_KEY: Optional; used for price oracle
# Run all tests
npm test
# Run tests for a specific file
npm test -- webhooks.routes.test.js
# Run tests matching a pattern
npm test -- --testNamePattern="rejects unknown"
# Watch mode (re-run on file changes)
npm test -- --watchTests cover:
- REST endpoint contracts
- Validation schemas
- Service logic (price oracle, webhooks, indexer)
- Database migrations
- Error handling
test/webhooks.routes.test.js- Webhook endpoint teststest/health.test.js- Health check teststest/api-docs.test.js- OpenAPI spec validationtest/webhookEvents.test.js- Event type validationtest/circuitBreaker.test.js- Circuit breaker logic
A minimal ESLint config is provided to catch common issues. The config is lightweight by design (Issue #231).
# Lint all source files
npx eslint .
# Auto-fix fixable issues
npx eslint . --fixCurrent Rules:
no-unused-vars: warn
Feel free to propose additions to .eslintrc.js as the codebase evolves.
The OpenAPI specification is linted during CI to ensure it's valid and well-formed:
# Lint the OpenAPI spec
npx @redocly/cli lint openapi.yaml- Formatting: 2-space indentation, use semicolons
- Variable naming: camelCase for variables and functions, snake_case for database columns
- Comments: Use JSDoc for complex functions; inline comments for non-obvious logic
- Error handling: Always provide descriptive error messages; include request IDs in logs
Migrations are managed via Knex.js. The migration system includes safeguards to prevent accidental schema changes in production.
# Apply pending migrations
npm run migrate
# Preview migrations without applying (dry run)
npm run migrate:dry-run
# Check migration status
npm run migrate:status
# Roll back the last batch of migrations
npm run migrate:rollbackMigration files are in src/db/migrations/. To create a new migration:
npx knex migrate:make migration_nameExample migration structure:
'use strict';
exports.up = async (knex) => {
return knex.schema.createTable('my_table', (table) => {
table.increments('id').primary();
table.string('name').notNullable();
table.timestamps(true, true);
});
};
exports.down = async (knex) => {
return knex.schema.dropTable('my_table');
};Important: Migrations run on production; test your rollback steps locally before submitting.
- Create feature branches off
main - Use descriptive branch names:
feature/webhook-retry,fix/price-anomaly,docs/contributing - Keep branches focused on a single issue or feature
# Ensure you're on the latest main
git checkout main
git pull origin main
# Create a new feature branch
git checkout -b feature/your-feature-name
# Make changes and commit
git add src/
git commit -m "feat: describe your change"
# Keep your branch up to date
git rebase origin/main- Tests pass locally: Run
npm testand ensure all tests pass - Linting passes: Run
npx eslint .with no errors - OpenAPI spec is valid: Run
npx @redocly/cli lint openapi.yaml - Migrations tested: If adding migrations, verify
npm run migrateandnpm run migrate:rollbackwork - Code is documented: Add comments for complex logic; update OpenAPI spec if endpoints change
- Branch is up to date: Rebase on
mainif there are conflicts
- Push your branch:
git push origin feature/your-feature-name - Open a PR on GitHub with a clear title and description
- Link any related issues: "Closes #123"
Use semantic commit prefixes:
feat:- New featurefix:- Bug fixdocs:- Documentationrefactor:- Code refactoring (no behavior change)test:- Test additions or updatesperf:- Performance improvementschore:- Build, CI, or dependency updates
Examples:
feat: add webhook signature verificationfix: handle null issuer in price queriesdocs: improve CONTRIBUTING.md
Include:
- What changed: Describe the feature or bug fix
- Why: Explain the motivation or problem being solved
- How to test: Step-by-step instructions to verify the change
- Related issues: Reference any GitHub issues
- Breaking changes: Call out any backward-incompatible changes
Example:
## Description
Adds webhook event type validation to prevent typos in subscription filters.
## Problem
Users could register webhooks with invalid event types (e.g., "foo.bar"),
resulting in subscriptions that never fire.
## Solution
- Enhanced `webhookSubscriptionSchema` to validate against known event types
- Improved error messages to show which events are invalid and what's valid
## Testing
1. Open Swagger UI at /api-docs
2. POST /api/v1/webhooks with events: ["invalid.event"]
3. Verify 400 response with helpful error message listing valid events
Closes #123Commits should follow the conventional commits format for consistency with automated changelog generation:
<type>(<scope>): <subject>
<body>
<footer>
feat: A new featurefix: A bug fixdocs: Documentation only changesrefactor: A code change that neither fixes a bug nor adds a featuretest: Adding missing or correcting testsperf: A code change that improves performancechore: Changes to build process, dependencies, or CI configuration
Scope clarifies what part of the codebase is affected:
webhookspricesindexerauthmigrationstestsapi-docs
git commit -m "feat(webhooks): add event type validation"
git commit -m "fix(prices): handle null issuer in circuit breaker"
git commit -m "docs(contributing): add development setup guide"
git commit -m "test(auth): improve API key middleware coverage"
git commit -m "refactor(cache): simplify Redis connection logic"All commits to main and pull requests automatically trigger:
- Lint OpenAPI spec - Validates
openapi.yaml - Lint source code - ESLint checks (warnings do not block)
- Run tests - Full test suite with Redis available
- Test migrations - Ensures migrations run and rollback cleanly
- Build Docker image - Verifies the production Docker image builds
A PR must pass all required checks before it can be merged.
Ensure Redis is running:
# If using Docker Compose
docker-compose up -d redis
# If using local Redis
redis-serverCheck that PostgreSQL is running and the DATABASE_URL is correct:
echo $DATABASE_URL
psql $DATABASE_URL -c "SELECT 1"If port 4000 (API), 6379 (Redis), or 5432 (PostgreSQL) are in use:
# Option 1: Kill the process
lsof -ti:4000 | xargs kill -9
# Option 2: Use different ports
PORT=4001 npm run dev
REDIS_PORT=6380 redis-serverVerify you're using Node 20.9.0 or higher:
node --version # Should be v20.9.0+
# Use nvm to switch versions
nvm install 20
nvm use 20- Questions: Open a GitHub Discussion
- Bug reports: Open a GitHub Issue with reproduction steps
- Security issues: Email security@smartdrop.app (do not open a public issue)
Be respectful and inclusive. We're all here to build something great together.
Thank you for contributing to SmartDrop! 🎉