Thanks for your interest in contributing! This guide covers how to set up the project and submit changes.
- .NET 10 SDK
- Node.js 20+ and Yarn
- Docker (for PostgreSQL)
docker compose -f docker/docker-compose.dev.yml up -dThis starts PostgreSQL 17 on localhost:5432 (user: postgres, password: postgres, database: webhookengine).
dotnet build WebhookEngine.sln
dotnet run --project src/WebhookEngine.APIThe API starts at http://localhost:5128. Database migrations are applied automatically on startup.
cd src/dashboard
yarn install
yarn devThe dev server starts at http://localhost:5173 and proxies API requests to localhost:5128.
For production builds:
yarn buildThis outputs to the API's wwwroot/ directory.
# All tests
dotnet test WebhookEngine.sln
# Specific project
dotnet test tests/WebhookEngine.Core.Tests
# Specific test
dotnet test --filter "FullyQualifiedName~ClassName.MethodName"Integration tests use Testcontainers and require Docker running.
src/
WebhookEngine.Core/ # Domain: entities, enums, interfaces
WebhookEngine.Infrastructure/ # EF Core, PostgreSQL queue, repositories
WebhookEngine.Application/ # DI registration (CQRS scaffold — not yet active)
WebhookEngine.Worker/ # Background services (delivery, retry, etc.)
WebhookEngine.API/ # ASP.NET Core host, controllers, middleware
WebhookEngine.Sdk/ # .NET SDK (NuGet package)
dashboard/ # React SPA (Vite + TypeScript + Tailwind)
tests/
*.Tests/ # xUnit test projects
samples/
WebhookEngine.Sample.Sender/ # SDK usage demo
WebhookEngine.Sample.Receiver/ # Webhook consumer with signature verification
signature-verification/ # Copy-paste signature verification (C#, TS, Python)
- PascalCase for classes, methods, properties
_camelCasefor private fieldsAsyncsuffix on all async methods- Constructor injection everywhere — no service locator pattern
- Pass
CancellationTokenthrough all async chains - Use
IHttpClientFactory— nevernew HttpClient() AsNoTracking()on read-only EF Core queries
- Yarn only (not npm or pnpm)
- Tailwind CSS v4 for styling
- Lucide React for icons
- ESLint + TypeScript strict mode
Before starting work on a feature or bug fix, check existing issues or open a new one to discuss the approach.
- Fork the repository
- Create a feature branch from
main(git checkout -b feature/my-change) - Make your changes
- Ensure the build passes:
dotnet build WebhookEngine.sln - Ensure tests pass:
dotnet test WebhookEngine.sln - Ensure the dashboard builds:
cd src/dashboard && yarn build - Commit with a clear message describing the change
- Open a pull request against
main
- Keep PRs focused — one feature or fix per PR
- Include relevant tests for new functionality
- Update documentation if you change public APIs
- Follow existing code style and naming conventions
- Add a description explaining why the change is needed, not just what changed
Key architectural constraints to keep in mind:
- Single process: API, workers, and dashboard are all served from one ASP.NET Core host
- PostgreSQL only: No Redis, RabbitMQ, or other dependencies for the core product
- At-least-once delivery: Messages may be delivered more than once but never lost
- Standard Webhooks: Signature format follows the Standard Webhooks specification
For more details, see docs/ARCHITECTURE.md.
By contributing, you agree that your contributions will be licensed under the MIT License.