Webhook Ingestion Flow
The dashboard is driven entirely by GitHub webhook events — it does not poll the GitHub API in normal operation.
Setup
A webhook must be configured on the source GitHub repo (e.g. AkerBP/wise) to send events to:
POST https://<your-dashboard>/api/webhook
The webhook secret must match the WEBHOOK_SECRET env var on the dashboard.
Required event types
| Event | Purpose |
|---|---|
pull_request | Ingest PR open/merge/close and fetch firstCommitAt |
projects_v2_item | Detect when an issue moves to the “released” column → stamp deployedAt |
Request flow
GitHub → POST /api/webhook
↓
webhookMiddleware validates X-Hub-Signature-256 HMAC
↓
webhookController reads X-GitHub-Event header, delegates
↓
webhookService routes by event type
├── pull_request → pullRequestService.ingest()
└── projects_v2_item → deploymentService.handleRelease()
pull_request event
Fires on opened, closed (merged), and synchronize.
On opened:
- Upsert the PR record in
pull_requests. - Fetch the branch’s commit list from GitHub REST API (
GET /repos/{owner}/{repo}/pulls/{number}/commits). - Take the earliest commit’s
commit.author.dateasfirstCommitAt.
On closed with merged: true:
- Set
mergedAton the PR record.
projects_v2_item event (deployment signal)
Fires when any field on a GitHub Projects item changes.
The handler:
- Checks
action === 'edited'andchanges.field_value.field_name === 'Status'. - Reads
changes.field_value.to.name(the new status value). - Compares to the configured
released_column_namefromapp_settings(default"Released"). - If it matches:
- Resolves the linked issue number from
content_urlin the event payload. - Finds all merged PRs linked to that issue (via
Closes #Nkeywords, stored during PR ingestion). - Stamps
deployedAt = event.projects_v2_item.updated_aton each matched PR.
- Resolves the linked issue number from
Signature validation
Every incoming request is validated with HMAC-SHA256:
X-Hub-Signature-256: sha256=<hex>
The signature is computed over the raw request body using WEBHOOK_SECRET. Requests that fail validation are rejected with 401.
Env vars
| Var | Purpose |
|---|---|
WEBHOOK_SECRET | GitHub webhook secret for HMAC validation |
GH_TOKEN | PAT with repo + read:project scope — used to resolve issue→PR links via GraphQL |
GH_OWNER | Owner of the source repo (e.g. AkerBP) |
GH_REPO | Name of the source repo (e.g. wise) |