Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 29 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Geo Webhook Server

Minimal webhook receiver for the [Geo notification service](https://github.com/geobrowser/gaia). Receives signed governance and bounty event notifications from the delivery-worker and processes them.
Minimal webhook receiver for the [Geo notification service](https://github.com/geobrowser/gaia). Receives signed governance and bounty event notifications from the delivery-worker, forwards them as rich embeds to a Discord webhook, and deploys to Cloudflare Workers. Both the Discord integration and Cloudflare deployment are reference defaults — swap them out for your app's needs (e.g. Slack, email, AWS Lambda).

## Stack

- **Bun** — TypeScript runtime (no transpilation, fast startup)
- **Hono** — Lightweight HTTP framework
- **[@geoprotocol/geo-sdk](https://github.com/geobrowser/geo-sdk)** — Geo protocol system IDs and entity types
- **Docker** — Single-stage production image

## Quick start
Expand All @@ -26,7 +27,20 @@ bun run start # production
bun test
```

## Deploy with Docker
## Deploy

### Cloudflare Workers (default)

```bash
# Set secrets
wrangler secret put GEO_WEBHOOK_SECRET
wrangler secret put DISCORD_WEBHOOK_URL

# Deploy
bun run deploy
```

### Docker

```bash
docker build -t geo-webhook-server .
Expand All @@ -47,21 +61,24 @@ Edit `src/handlers.ts` — each event type has its own function. Add push notifi
## Event types

### Governance
- `proposal_created` — new proposal in a space
- `proposal_updated` — proposal content changed
- `proposal_voted` — vote cast (includes `vote` and `voter_id`)
- `proposal_executed` — passed proposal executed on-chain
- `proposal_settings_updated` — voting settings changed
- `proposal_rejected` — proposal expired without execution
- `proposal_created` — new proposal in a space (`proposal_id`, `proposer_id`)
- `proposal_updated` — proposal content changed (`proposal_id`, `proposer_id`)
- `proposal_voted` — vote cast (`proposal_id`, `voter_id`, `vote`)
- `proposal_executed` — passed proposal executed on-chain (`proposal_id`)
- `proposal_settings_updated` — voting settings changed (`proposal_id`)
- `proposal_rejected` — proposal expired without execution (`proposal_id`, `proposer_id`)

### Bounty
- `bounty_interest` — curator expressed interest in a bounty
- `bounty_allocated` — bounty allocated to a curator
- `bounty_payout` — bounty paid out to a curator
- `bounty_interest` — curator expressed interest in a bounty (`bounty_entity_id`, `curator_space_id`, `bounty_space_id`, `interested_user_space_id`)
- `bounty_allocated` — bounty allocated to a curator (`bounty_entity_id`, `curator_space_id`, `bounty_space_id`, `proposal_id?`)
- `bounty_payout` — bounty paid out to a curator (`bounty_entity_id`, `curator_space_id`, `bounty_space_id`, `proposal_id?`)

All events include common fields: `space_id`, `event_type`, `category`, `idempotency_key`, `block_number`, `timestamp`, and optional enrichment fields (`space_name`, `bounty_name`, `curator_name`).

## Configuration

| Variable | Required | Default | Description |
|---|---|---|---|
| `GEO_WEBHOOK_SECRET` | Yes | — | Shared secret for HMAC verification |
| `PORT` | No | `3000` | Server port |
| `DISCORD_WEBHOOK_URL` | No | — | Discord webhook URL for forwarding notifications as embeds |
| `PORT` | No | `3000` | Server port (local dev only; Cloudflare Workers ignores this) |
Loading