All checks were successful
CI / build-test (push) Successful in 1m3s
- Introduced `compose.yml` for deployment, pulling the image from the registry - Added `compose.dev.yml` for local development, building the image from source - Updated `README.md` and `.claude/CLAUDE.md` with instructions for both configurations - Introduced `DB_PATH` environment variable to customize SQLite database file location - Updated `main.go` to use `DB_PATH` with a default fallback (`./diun.db`)
147 lines
4.4 KiB
Markdown
147 lines
4.4 KiB
Markdown
# DIUN Webhook Dashboard
|
|
|
|
A Go web app that receives [DIUN](https://crazymax.dev/diun/) webhook events and shows image updates in a modern dashboard. Events are persisted to SQLite so they survive restarts.
|
|
|
|
- Receives DIUN webhooks at `POST /webhook`
|
|
- Serves a React SPA dashboard at `/`
|
|
- REST API for updates, tags, and acknowledgements
|
|
- Persistent storage via SQLite (`diun.db`)
|
|
- Tag/group system to organize images
|
|
- Dismiss (acknowledge) updates you've reviewed
|
|
|
|
## Quick start
|
|
|
|
### Run locally (Go 1.26+)
|
|
```bash
|
|
# Build the frontend first
|
|
cd frontend && bun install && bun run build && cd ..
|
|
|
|
# Start the server
|
|
go run ./cmd/diunwebhook/
|
|
# open http://localhost:8080
|
|
```
|
|
|
|
### Docker
|
|
```bash
|
|
docker build -t diun-webhook-dashboard .
|
|
docker run --rm -p 8080:8080 diun-webhook-dashboard
|
|
# open http://localhost:8080
|
|
```
|
|
|
|
### Docker Compose (deploy)
|
|
```bash
|
|
# Pulls from Gitea registry, persists DB to a named volume
|
|
docker compose up -d
|
|
# open http://localhost:8080
|
|
```
|
|
|
|
### Docker Compose (dev)
|
|
```bash
|
|
# Builds the image locally from source
|
|
docker compose -f compose.dev.yml up -d
|
|
# open http://localhost:8080
|
|
```
|
|
|
|
## Webhook authentication
|
|
|
|
Set `WEBHOOK_SECRET` to protect the webhook endpoint with token authentication. When set, every `POST /webhook` must include a matching `Authorization` header. When unset, the webhook is open (a warning is logged at startup).
|
|
|
|
```bash
|
|
# Run with authentication
|
|
WEBHOOK_SECRET=your-secret-token-here go run ./cmd/diunwebhook/
|
|
|
|
# Or via Docker Compose (.env file or inline)
|
|
WEBHOOK_SECRET=your-secret-token-here docker compose up -d
|
|
|
|
# Custom database path (useful for Docker volume mounts)
|
|
DB_PATH=/data/diun.db go run ./cmd/diunwebhook/
|
|
```
|
|
|
|
## DIUN configuration example
|
|
Configure DIUN to send webhooks to this app. Example (YAML):
|
|
|
|
```yaml
|
|
notif:
|
|
webhook:
|
|
enable: true
|
|
endpoint: http://your-host-or-ip:8080/webhook
|
|
headers:
|
|
authorization: "your-secret-token-here"
|
|
```
|
|
|
|
Or via env: `DIUN_NOTIF_WEBHOOK_HEADERS_AUTHORIZATION=your-secret-token-here`
|
|
|
|
The `authorization` header value must match `WEBHOOK_SECRET` exactly.
|
|
|
|
Expected JSON payload (simplified):
|
|
```json
|
|
{
|
|
"image": "library/nginx",
|
|
"tag": "1.27.0",
|
|
"status": "new",
|
|
"time": "2026-02-23T16:00:00Z"
|
|
}
|
|
```
|
|
|
|
## API
|
|
|
|
| Method | Endpoint | Description |
|
|
|--------|----------|-------------|
|
|
| `POST` | `/webhook` | Accept a DIUN event JSON body |
|
|
| `GET` | `/api/updates` | Return all events (keyed by image) with tag and acknowledged state |
|
|
| `PATCH` | `/api/updates/{image}` | Mark an event as acknowledged (dismiss) |
|
|
| `GET` | `/api/tags` | List all tags |
|
|
| `POST` | `/api/tags` | Create a new tag |
|
|
| `DELETE` | `/api/tags/{id}` | Delete a tag (cascades to assignments) |
|
|
| `PUT` | `/api/tag-assignments` | Assign an image to a tag |
|
|
| `DELETE` | `/api/tag-assignments` | Unassign an image from its tag |
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
cmd/diunwebhook/ — main application entrypoint
|
|
pkg/diunwebhook/ — core library (handlers, DB, models)
|
|
frontend/ — React SPA (Bun + Vite + React 19 + Tailwind + shadcn/ui)
|
|
.gitea/workflows/ — CI/CD workflows (Gitea Actions)
|
|
Dockerfile — 3-stage multi-stage build
|
|
compose.yml — deploy compose (pulls from Gitea registry)
|
|
compose.dev.yml — dev compose (builds locally)
|
|
```
|
|
|
|
## Development
|
|
|
|
**Backend:**
|
|
```bash
|
|
go run ./cmd/diunwebhook/
|
|
```
|
|
|
|
**Frontend (dev server with hot reload):**
|
|
```bash
|
|
cd frontend
|
|
bun install
|
|
bun run dev # http://localhost:5173, proxies API to :8080
|
|
```
|
|
|
|
## Testing
|
|
|
|
Run unit tests and check coverage:
|
|
|
|
```bash
|
|
go test -v -coverprofile=coverage.out -coverpkg=./... ./...
|
|
```
|
|
|
|
Aim for 80-90% coverage. Coverage below 80% will emit a warning in CI but will not fail the pipeline.
|
|
|
|
## CI/CD with Gitea Actions
|
|
|
|
- **CI** (`.gitea/workflows/ci.yml`): Runs on push/PR to `develop`. Checks formatting (`gofmt`), runs `go vet`, tests with coverage, and builds the binary.
|
|
- **Release** (`.gitea/workflows/release.yml`): Manual dispatch. Runs tests, bumps version, tags, builds and pushes Docker image to Gitea registry, creates a release with changelog.
|
|
|
|
## Production notes
|
|
- Behind a reverse proxy, ensure the app is reachable at `/webhook` from DIUN.
|
|
- Data is persisted to `diun.db` in the working directory by default. Set `DB_PATH` to change the location (e.g. `DB_PATH=/data/diun.db`). The deploy compose file uses a named volume at `/data`.
|
|
- Set `WEBHOOK_SECRET` to protect the webhook endpoint if exposed publicly.
|
|
|
|
## License
|
|
MIT — see `LICENSE`.
|