CommunityPro / CommunityPro/community-pro-api

Contributors: org webhook receiver + ContributionEvent (Phase 5.1)

Open
#6 0 comments 0 reactions 0 assignees View on GitHub
contributors
Dominant language
C#
Stars
0
Forks
0
PR merge metrics
No merged PRs in 30d

Description

## Scope
New `CommunityPro.Contributors` module (schema `contributors`): receive org-level GitHub webhooks and record merged PRs. **Merged PRs are the main community metric.**

## Endpoint
`POST /webhooks/github/org` — validate `X-Hub-Signature-256` HMAC with a **separate** org webhook secret (new env var; add to `env.example`). Handle `pull_request` events where `action == "closed" && pull_request.merged == true`.

## Data model
```csharp
public sealed class ContributionEvent
{
public Guid Id { get; set; }
public long GithubUserId { get; set; } // numeric id — the identity key (logins get renamed)
public string GithubLogin { get; set; } // display only, refresh freely
public string Repo { get; set; }
public long PrNumber { get; set; }
public DateTimeOffset MergedAt { get; set; }
}
```

## Idempotency (non-negotiable)
GitHub redelivers. Record `X-GitHub-Delivery` GUIDs in a per-source delivery table with a unique-constraint insert as the guard — copy the Phase 1 practice-repo webhook pattern (see the Identity module's webhook handling). Also add a unique constraint on `(Repo, PrNumber)` as a second layer.

## Error codes
`webhooks.invalid_signature` (401), replays → 200 no-op

## Acceptance criteria
- [ ] Invalid/missing HMAC rejected; valid signature verified against raw body bytes
- [ ] Replayed delivery id is a no-op; duplicate repo+PR is a no-op
- [ ] Non-merge closes ignored
- [ ] xUnit coverage incl. signature validation and idempotency races

### Conventions (project-wide, non-negotiable)
- .NET 9, records for immutable shapes, file-scoped namespaces, primary constructors where they read well. Minimal-API endpoints grouped per module via `IEndpointModule.MapEndpoints`.
- `Result` (SharedKernel) instead of exception-driven control flow. Endpoint results map failures to ProblemDetails with the stable error codes listed above — the frontend keys off them.
- Module owns its EF Core `DbContext` mapped to its own Postgres schema. Modules never reference each other's internals — cross-module needs go through a public contract interface or an in-process domain event (`IEventPublisher`).
- All external calls (GitHub, Stripe, Brevo, Cloudinary, Meilisearch) behind interfaces owned by the consuming module.
- Every list endpoint paginated (offset is fine). xUnit tests in `tests/CommunityPro.Tests//` following the existing harness patterns (see `Members/MembersTestHarness.cs`).

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.