All checks were successful
CI / build-test (push) Successful in 1m2s
- Add `.gitignore` to exclude `node_modules/`, `.vitepress/cache/`, and `.vitepress/dist/` directories - Include `bun.lock` for dependency management with Bun
78 lines
4.0 KiB
Markdown
78 lines
4.0 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Commands
|
|
|
|
```bash
|
|
# Run all tests with coverage
|
|
go test -v -coverprofile=coverage.out -coverpkg=./... ./...
|
|
|
|
# Run a single test
|
|
go test -v -run TestWebhookHandler ./pkg/diunwebhook/
|
|
|
|
# Run the app locally
|
|
go run ./cmd/diunwebhook/
|
|
|
|
# Build Docker image
|
|
docker build -t diun-webhook-dashboard .
|
|
|
|
# Run with Docker Compose (deploy — pulls from registry)
|
|
docker compose up -d
|
|
|
|
# Run with Docker Compose (dev — builds locally)
|
|
docker compose -f compose.dev.yml up -d
|
|
|
|
# Frontend (from frontend/ directory)
|
|
bun install # install deps
|
|
bun run dev # dev server on :5173 (proxies /api and /webhook to :8080)
|
|
bun run build # production build → frontend/dist/
|
|
|
|
# Documentation site (from docs/ directory)
|
|
bun install # install deps
|
|
bun run dev # VitePress dev server on :5174
|
|
bun run build # production build → docs/.vitepress/dist/
|
|
```
|
|
|
|
CI warns (but does not fail) when coverage drops below 80%.
|
|
|
|
## Architecture
|
|
|
|
The app is a Go HTTP server that receives [DIUN](https://crazymax.dev/diun/) webhook events and exposes them via a JSON API and a React SPA dashboard. Events are persisted to a SQLite database (`diun.db`) using `modernc.org/sqlite` (pure Go, no CGO).
|
|
|
|
**Package layout:**
|
|
- `pkg/diunwebhook/` — core library: `DiunEvent`, `UpdateEntry`, and `Tag` structs; SQLite-backed storage (guarded by `sync.Mutex`); HTTP handlers (`WebhookHandler`, `UpdatesHandler`, `DismissHandler`, `TagsHandler`, `TagByIDHandler`, `TagAssignmentHandler`)
|
|
- `cmd/diunwebhook/main.go` — calls `InitDB()`, wires handlers onto `net/http`'s default mux, serves `./frontend/dist` at `/`, listens on `:8080` (overridable via `PORT` env var), graceful shutdown
|
|
- `pkg/diunwebhook/diunwebhook_test.go` — external test package (`package diunwebhook_test`); uses `httptest` for handler tests
|
|
- `pkg/diunwebhook/export_test.go` — test-only exports
|
|
- `frontend/` — React SPA (Bun + Vite + React 19 + Tailwind CSS + shadcn/ui + dnd-kit)
|
|
- `docs/` — VitePress documentation site
|
|
- `CONTRIBUTING.md` — developer guide (project structure, development setup, testing, CI/CD)
|
|
|
|
**Database schema (SQLite):**
|
|
- `updates` — one row per image (PRIMARY KEY `image`), stores full event fields plus `received_at` and `acknowledged_at`
|
|
- `tags` — user-defined tag/group names (`id` INTEGER PK, `name` UNIQUE)
|
|
- `tag_assignments` — maps `image` → `tag_id` (FK with CASCADE delete)
|
|
|
|
**API routes:**
|
|
- `POST /webhook` — accept a DIUN event
|
|
- `GET /api/updates` — return all events (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 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
|
|
|
|
**Environment variables:**
|
|
- `PORT` — listen port (default `8080`)
|
|
- `DB_PATH` — path to SQLite database file (default `./diun.db`); set to e.g. `/data/diun.db` in Docker to use a separate mountable directory
|
|
- `WEBHOOK_SECRET` — when set, every `POST /webhook` must include a matching `Authorization` header; when unset, the webhook is open (a warning is logged at startup)
|
|
|
|
**Key data flow:**
|
|
1. DIUN POSTs JSON to `/webhook` → `WebhookHandler` decodes into `DiunEvent` → upserted into `updates` table (latest event per image wins, resets acknowledged state)
|
|
2. React SPA polls `GET /api/updates` every 5 s → `UpdatesHandler` returns map of `UpdateEntry` (includes event, received time, acknowledged flag, and optional tag)
|
|
3. User can dismiss updates via `PATCH /api/updates/{image}` and organize images into tag groups via the tag/assignment endpoints
|
|
|
|
**Test helpers exposed from the library package** (not part of the public API, only for tests): `GetUpdatesMap()`, `UpdatesReset()`, `UpdateEvent()`, `ResetTags()`.
|