fix: correct 4 factual inaccuracies in README
All checks were successful
check / check (push) Successful in 1m2s
All checks were successful
check / check (push) Successful in 1m2s
- Fix webhook route: /hooks/<uuid> → /webhook/{uuid} (matches routes.go)
- Fix CGO claims: acknowledge mattn/go-sqlite3 transitive dep requires CGO at build time
- Fix database architecture: distinguish current single-DB from planned Phase 2 per-webhook split
- Fix static file descriptions: Bootstrap CSS/jQuery JS → actual style.css and app.js
This commit is contained in:
64
README.md
64
README.md
@@ -150,8 +150,10 @@ It uses:
|
|||||||
lifecycle management
|
lifecycle management
|
||||||
- **[go-chi](https://github.com/go-chi/chi)** for HTTP routing
|
- **[go-chi](https://github.com/go-chi/chi)** for HTTP routing
|
||||||
- **[GORM](https://gorm.io)** for database access with
|
- **[GORM](https://gorm.io)** for database access with
|
||||||
**[modernc.org/sqlite](https://pkg.go.dev/modernc.org/sqlite)** (pure
|
**[modernc.org/sqlite](https://pkg.go.dev/modernc.org/sqlite)** as
|
||||||
Go, no CGO) as the storage backend
|
the runtime SQLite driver. Note: `gorm.io/driver/sqlite` transitively
|
||||||
|
depends on `mattn/go-sqlite3`, which requires CGO at build time (see
|
||||||
|
[Docker](#docker) section)
|
||||||
- **[slog](https://pkg.go.dev/log/slog)** (stdlib) for structured
|
- **[slog](https://pkg.go.dev/log/slog)** (stdlib) for structured
|
||||||
logging with TTY detection (text for dev, JSON for prod)
|
logging with TTY detection (text for dev, JSON for prod)
|
||||||
- **[gorilla/sessions](https://github.com/gorilla/sessions)** for
|
- **[gorilla/sessions](https://github.com/gorilla/sessions)** for
|
||||||
@@ -198,7 +200,7 @@ tier** (event ingestion, delivery, and logging).
|
|||||||
|
|
||||||
┌─────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
│ EVENT TIER │
|
│ EVENT TIER │
|
||||||
│ (per-webhook dedicated database) │
|
│ (planned: per-webhook dedicated database) │
|
||||||
│ │
|
│ │
|
||||||
│ ┌──────────┐ ┌──────────┐ ┌─────────────────┐ │
|
│ ┌──────────┐ ┌──────────┐ ┌─────────────────┐ │
|
||||||
│ │ Event │──1:N──│ Delivery │──1:N──│ DeliveryResult │ │
|
│ │ Event │──1:N──│ Delivery │──1:N──│ DeliveryResult │ │
|
||||||
@@ -254,7 +256,7 @@ the full request and creates an Event.
|
|||||||
| -------------- | ------- | ----------- |
|
| -------------- | ------- | ----------- |
|
||||||
| `id` | UUID | Primary key |
|
| `id` | UUID | Primary key |
|
||||||
| `processor_id` | UUID | Foreign key → Webhook |
|
| `processor_id` | UUID | Foreign key → Webhook |
|
||||||
| `path` | string | Unique URL path (UUID-based, e.g. `/hooks/<uuid>`) |
|
| `path` | string | Unique URL path (UUID-based, e.g. `/webhook/{uuid}`) |
|
||||||
| `description` | string | Optional description |
|
| `description` | string | Optional description |
|
||||||
| `active` | boolean | Whether this entrypoint accepts events (default: true) |
|
| `active` | boolean | Whether this entrypoint accepts events (default: true) |
|
||||||
|
|
||||||
@@ -387,12 +389,21 @@ All entities include these fields from `BaseModel`:
|
|||||||
|
|
||||||
### Database Architecture
|
### Database Architecture
|
||||||
|
|
||||||
webhooker uses **separate SQLite database files** rather than a single
|
#### Current Implementation
|
||||||
monolithic database. This is a deliberate architectural choice.
|
|
||||||
|
|
||||||
#### Main Application Database
|
webhooker currently uses a **single SQLite database** for all data —
|
||||||
|
application configuration, user accounts, and (once implemented) event
|
||||||
|
storage. The database connection is managed by GORM with a single
|
||||||
|
connection string configured via `DBURL`. On first startup the database
|
||||||
|
is auto-migrated and an `admin` user is created.
|
||||||
|
|
||||||
A single SQLite file stores all application-level data:
|
#### Planned: Per-Webhook Event Databases (Phase 2)
|
||||||
|
|
||||||
|
In a future phase (see TODO Phase 2 below), webhooker will split into
|
||||||
|
**separate SQLite database files**: a main application database for
|
||||||
|
configuration data and per-webhook databases for event storage.
|
||||||
|
|
||||||
|
**Main Application Database** — will store:
|
||||||
|
|
||||||
- **Users** — accounts and Argon2id password hashes
|
- **Users** — accounts and Argon2id password hashes
|
||||||
- **Webhooks** (Processors) — webhook configurations
|
- **Webhooks** (Processors) — webhook configurations
|
||||||
@@ -400,18 +411,14 @@ A single SQLite file stores all application-level data:
|
|||||||
- **Targets** — delivery destination configurations
|
- **Targets** — delivery destination configurations
|
||||||
- **APIKeys** — programmatic access credentials
|
- **APIKeys** — programmatic access credentials
|
||||||
|
|
||||||
This database is small, low-write, and contains the configuration that
|
**Per-Webhook Event Databases** — each webhook will get its own
|
||||||
defines how the application behaves. It is backed up as a single file.
|
dedicated SQLite file containing:
|
||||||
|
|
||||||
#### Per-Webhook Event Databases
|
|
||||||
|
|
||||||
Each webhook gets its own dedicated SQLite database file containing:
|
|
||||||
|
|
||||||
- **Events** — captured incoming webhook payloads
|
- **Events** — captured incoming webhook payloads
|
||||||
- **Deliveries** — event-to-target pairings and their status
|
- **Deliveries** — event-to-target pairings and their status
|
||||||
- **DeliveryResults** — individual delivery attempt logs
|
- **DeliveryResults** — individual delivery attempt logs
|
||||||
|
|
||||||
This separation provides:
|
This planned separation will provide:
|
||||||
|
|
||||||
- **Isolation** — a high-volume webhook won't cause lock contention or
|
- **Isolation** — a high-volume webhook won't cause lock contention or
|
||||||
WAL bloat affecting the main application or other webhooks.
|
WAL bloat affecting the main application or other webhooks.
|
||||||
@@ -421,22 +428,23 @@ This separation provides:
|
|||||||
- **Clean deletion** — removing a webhook and all its history is as
|
- **Clean deletion** — removing a webhook and all its history is as
|
||||||
simple as deleting one file.
|
simple as deleting one file.
|
||||||
- **Per-webhook retention** — the `retention_days` field on each webhook
|
- **Per-webhook retention** — the `retention_days` field on each webhook
|
||||||
controls automatic cleanup of old events in that webhook's database
|
will control automatic cleanup of old events in that webhook's
|
||||||
only.
|
database only.
|
||||||
- **Performance** — each webhook's database has its own WAL, its own
|
- **Performance** — each webhook's database will have its own WAL, its
|
||||||
page cache, and its own lock, so concurrent event ingestion across
|
own page cache, and its own lock, so concurrent event ingestion across
|
||||||
webhooks never contends.
|
webhooks won't contend.
|
||||||
|
|
||||||
All databases use the pure-Go SQLite driver
|
The database uses the
|
||||||
([modernc.org/sqlite](https://pkg.go.dev/modernc.org/sqlite)) — no CGO
|
[modernc.org/sqlite](https://pkg.go.dev/modernc.org/sqlite) driver at
|
||||||
required.
|
runtime, though CGO is required at build time due to the transitive
|
||||||
|
`mattn/go-sqlite3` dependency from `gorm.io/driver/sqlite`.
|
||||||
|
|
||||||
### Request Flow
|
### Request Flow
|
||||||
|
|
||||||
```
|
```
|
||||||
External Service
|
External Service
|
||||||
│
|
│
|
||||||
│ POST /hooks/<uuid>
|
│ POST /webhook/{uuid}
|
||||||
▼
|
▼
|
||||||
┌─────────────┐ ┌──────────────┐ ┌──────────────┐
|
┌─────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||||
│ chi Router │────►│ Middleware │────►│ Webhook │
|
│ chi Router │────►│ Middleware │────►│ Webhook │
|
||||||
@@ -484,7 +492,7 @@ against a misbehaving sender).
|
|||||||
| `GET` | `/` | Web UI index page (server-rendered) |
|
| `GET` | `/` | Web UI index page (server-rendered) |
|
||||||
| `GET` | `/.well-known/healthcheck` | Health check (JSON: status, uptime, version) |
|
| `GET` | `/.well-known/healthcheck` | Health check (JSON: status, uptime, version) |
|
||||||
| `GET` | `/s/*` | Static file serving (embedded CSS, JS) |
|
| `GET` | `/s/*` | Static file serving (embedded CSS, JS) |
|
||||||
| `ANY` | `/hooks/<uuid>` | Webhook receiver endpoint (POST only; others return 405) |
|
| `ANY` | `/webhook/{uuid}` | Webhook receiver endpoint (accepts all methods) |
|
||||||
|
|
||||||
#### Authentication Endpoints
|
#### Authentication Endpoints
|
||||||
|
|
||||||
@@ -579,8 +587,8 @@ webhooker/
|
|||||||
├── pkg/config/ # Reusable multi-environment config library
|
├── pkg/config/ # Reusable multi-environment config library
|
||||||
├── static/
|
├── static/
|
||||||
│ ├── static.go # //go:embed directive
|
│ ├── static.go # //go:embed directive
|
||||||
│ ├── css/ # Bootstrap CSS
|
│ ├── css/style.css # Custom stylesheet (system font stack, card effects, layout)
|
||||||
│ └── js/ # Bootstrap + jQuery JS
|
│ └── js/app.js # Client-side JavaScript (minimal bootstrap)
|
||||||
├── templates/ # Go HTML templates (base, index, login, etc.)
|
├── templates/ # Go HTML templates (base, index, login, etc.)
|
||||||
├── configs/
|
├── configs/
|
||||||
│ └── config.yaml.example # Example configuration file
|
│ └── config.yaml.example # Example configuration file
|
||||||
@@ -662,7 +670,7 @@ linted, tested, and compiled.
|
|||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
### Phase 1: Core Webhook Engine
|
### Phase 1: Core Webhook Engine
|
||||||
- [ ] Implement webhook reception and event storage at `/hooks/<uuid>`
|
- [ ] Implement webhook reception and event storage at `/webhook/{uuid}`
|
||||||
- [ ] Build event processing and target delivery engine
|
- [ ] Build event processing and target delivery engine
|
||||||
- [ ] Implement HTTP target type (fire-and-forget POST)
|
- [ ] Implement HTTP target type (fire-and-forget POST)
|
||||||
- [ ] Implement retry target type (exponential backoff)
|
- [ ] Implement retry target type (exponential backoff)
|
||||||
|
|||||||
Reference in New Issue
Block a user