rework: migrate module path, fix healthcheck URL, add architecture notes
All checks were successful
check / check (push) Successful in 1m57s
All checks were successful
check / check (push) Successful in 1m57s
- Migrate Go module path from git.eeqj.de/sneak/webhooker to sneak.berlin/go/webhooker (go.mod, pkg/config/go.mod, all imports) - Drop .json extension from healthcheck endpoint: /.well-known/healthcheck (routes.go, Dockerfile HEALTHCHECK, README) - Add Rate Limiting section to README Design: global rate limiting must not apply to webhook endpoints; per-webhook configurable limits instead - Add Database Architecture section to README Design: separate SQLite files for main app config vs per-processor data (input logs, processor logs, output queues) Addresses review feedback from sneak on PR #6.
This commit is contained in:
parent
18cfedb81c
commit
69bbc958a7
@ -64,6 +64,6 @@ USER webhooker
|
||||
EXPOSE 8080
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/.well-known/healthcheck.json || exit 1
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/.well-known/healthcheck || exit 1
|
||||
|
||||
CMD ["./webhooker"]
|
||||
|
||||
35
README.md
35
README.md
@ -66,6 +66,39 @@ application lifecycle. It uses `log/slog` for structured logging, GORM
|
||||
for database access, and SQLite (via `modernc.org/sqlite`, pure Go, no
|
||||
CGO) for storage. HTTP routing uses chi.
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
Global rate limiting middleware (e.g. per-IP throttling applied at the
|
||||
router level) must **not** apply to webhook receiver endpoints
|
||||
(`/webhook/{uuid}`). Webhook endpoints receive automated traffic from
|
||||
external services at unpredictable rates, and blanket rate limits would
|
||||
cause legitimate webhook deliveries to be dropped.
|
||||
|
||||
Instead, each webhook endpoint has its own individually configurable rate
|
||||
limit, applied within the webhook handler itself. By default, no rate
|
||||
limit is applied — webhook endpoints accept traffic as fast as it arrives.
|
||||
Rate limits can be configured on a per-webhook basis in the application
|
||||
when needed (e.g. to protect against a misbehaving sender).
|
||||
|
||||
### Database Architecture
|
||||
|
||||
webhooker uses separate SQLite database files rather than a single
|
||||
monolithic database:
|
||||
|
||||
- **Main application database** — Stores application configuration and
|
||||
all standard webapp data: users, sessions, API keys, and global
|
||||
settings.
|
||||
- **Per-processor databases** — Each processor (working name — a better
|
||||
term is needed) gets its own dedicated SQLite database file containing:
|
||||
input logs, processor logs, and all output queues for that specific
|
||||
processor.
|
||||
|
||||
This separation provides several benefits: processor databases can be
|
||||
independently backed up, rotated, or archived; a high-volume processor
|
||||
won't cause lock contention or bloat affecting the main application; and
|
||||
individual processor data can be cleanly deleted when a processor is
|
||||
removed.
|
||||
|
||||
### Package Layout
|
||||
|
||||
All application code lives under `internal/` to prevent external imports.
|
||||
@ -98,7 +131,7 @@ The main entry point is `cmd/webhooker/main.go`.
|
||||
### API Endpoints
|
||||
|
||||
- `GET /` — Web UI index page
|
||||
- `GET /.well-known/healthcheck.json` — Health check with uptime, version
|
||||
- `GET /.well-known/healthcheck` — Health check with uptime, version
|
||||
- `GET /s/*` — Static file serving (CSS, JS)
|
||||
- `GET /metrics` — Prometheus metrics (requires basic auth)
|
||||
- `POST /webhook/{uuid}` — Webhook receiver endpoint
|
||||
|
||||
@ -3,16 +3,16 @@ package main
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/internal/config"
|
||||
"git.eeqj.de/sneak/webhooker/internal/database"
|
||||
"git.eeqj.de/sneak/webhooker/internal/globals"
|
||||
"git.eeqj.de/sneak/webhooker/internal/handlers"
|
||||
"git.eeqj.de/sneak/webhooker/internal/healthcheck"
|
||||
"git.eeqj.de/sneak/webhooker/internal/logger"
|
||||
"git.eeqj.de/sneak/webhooker/internal/middleware"
|
||||
"git.eeqj.de/sneak/webhooker/internal/server"
|
||||
"git.eeqj.de/sneak/webhooker/internal/session"
|
||||
"go.uber.org/fx"
|
||||
"sneak.berlin/go/webhooker/internal/config"
|
||||
"sneak.berlin/go/webhooker/internal/database"
|
||||
"sneak.berlin/go/webhooker/internal/globals"
|
||||
"sneak.berlin/go/webhooker/internal/handlers"
|
||||
"sneak.berlin/go/webhooker/internal/healthcheck"
|
||||
"sneak.berlin/go/webhooker/internal/logger"
|
||||
"sneak.berlin/go/webhooker/internal/middleware"
|
||||
"sneak.berlin/go/webhooker/internal/server"
|
||||
"sneak.berlin/go/webhooker/internal/session"
|
||||
)
|
||||
|
||||
// Build-time variables set via -ldflags.
|
||||
|
||||
6
go.mod
6
go.mod
@ -1,11 +1,10 @@
|
||||
module git.eeqj.de/sneak/webhooker
|
||||
module sneak.berlin/go/webhooker
|
||||
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.24.1
|
||||
|
||||
require (
|
||||
git.eeqj.de/sneak/webhooker/pkg/config v0.0.0-00010101000000-000000000000
|
||||
github.com/99designs/basicauth-go v0.0.0-20230316000542-bf6f9cbbf0f8
|
||||
github.com/getsentry/sentry-go v0.25.0
|
||||
github.com/go-chi/chi v1.5.5
|
||||
@ -22,6 +21,7 @@ require (
|
||||
gorm.io/driver/sqlite v1.5.4
|
||||
gorm.io/gorm v1.25.5
|
||||
modernc.org/sqlite v1.28.0
|
||||
sneak.berlin/go/webhooker/pkg/config v0.0.0-00010101000000-000000000000
|
||||
)
|
||||
|
||||
require (
|
||||
@ -85,4 +85,4 @@ require (
|
||||
modernc.org/token v1.0.1 // indirect
|
||||
)
|
||||
|
||||
replace git.eeqj.de/sneak/webhooker/pkg/config => ./pkg/config
|
||||
replace sneak.berlin/go/webhooker/pkg/config => ./pkg/config
|
||||
|
||||
@ -5,10 +5,10 @@ import (
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/internal/globals"
|
||||
"git.eeqj.de/sneak/webhooker/internal/logger"
|
||||
pkgconfig "git.eeqj.de/sneak/webhooker/pkg/config"
|
||||
"go.uber.org/fx"
|
||||
"sneak.berlin/go/webhooker/internal/globals"
|
||||
"sneak.berlin/go/webhooker/internal/logger"
|
||||
pkgconfig "sneak.berlin/go/webhooker/pkg/config"
|
||||
|
||||
// spooky action at a distance!
|
||||
// this populates the environment
|
||||
|
||||
@ -4,14 +4,14 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/internal/globals"
|
||||
"git.eeqj.de/sneak/webhooker/internal/logger"
|
||||
pkgconfig "git.eeqj.de/sneak/webhooker/pkg/config"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/fx"
|
||||
"go.uber.org/fx/fxtest"
|
||||
"sneak.berlin/go/webhooker/internal/globals"
|
||||
"sneak.berlin/go/webhooker/internal/logger"
|
||||
pkgconfig "sneak.berlin/go/webhooker/pkg/config"
|
||||
)
|
||||
|
||||
// createTestConfig creates a test configuration file in memory
|
||||
|
||||
@ -5,12 +5,12 @@ import (
|
||||
"database/sql"
|
||||
"log/slog"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/internal/config"
|
||||
"git.eeqj.de/sneak/webhooker/internal/logger"
|
||||
"go.uber.org/fx"
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
_ "modernc.org/sqlite" // Pure Go SQLite driver
|
||||
"sneak.berlin/go/webhooker/internal/config"
|
||||
"sneak.berlin/go/webhooker/internal/logger"
|
||||
)
|
||||
|
||||
// nolint:revive // DatabaseParams is a standard fx naming convention
|
||||
|
||||
@ -4,12 +4,12 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/internal/config"
|
||||
"git.eeqj.de/sneak/webhooker/internal/globals"
|
||||
"git.eeqj.de/sneak/webhooker/internal/logger"
|
||||
pkgconfig "git.eeqj.de/sneak/webhooker/pkg/config"
|
||||
"github.com/spf13/afero"
|
||||
"go.uber.org/fx/fxtest"
|
||||
"sneak.berlin/go/webhooker/internal/config"
|
||||
"sneak.berlin/go/webhooker/internal/globals"
|
||||
"sneak.berlin/go/webhooker/internal/logger"
|
||||
pkgconfig "sneak.berlin/go/webhooker/pkg/config"
|
||||
)
|
||||
|
||||
func TestDatabaseConnection(t *testing.T) {
|
||||
|
||||
@ -3,7 +3,7 @@ package handlers
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/internal/database"
|
||||
"sneak.berlin/go/webhooker/internal/database"
|
||||
)
|
||||
|
||||
// HandleLoginPage returns a handler for the login page (GET)
|
||||
|
||||
@ -7,12 +7,12 @@ import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/internal/database"
|
||||
"git.eeqj.de/sneak/webhooker/internal/globals"
|
||||
"git.eeqj.de/sneak/webhooker/internal/healthcheck"
|
||||
"git.eeqj.de/sneak/webhooker/internal/logger"
|
||||
"git.eeqj.de/sneak/webhooker/internal/session"
|
||||
"go.uber.org/fx"
|
||||
"sneak.berlin/go/webhooker/internal/database"
|
||||
"sneak.berlin/go/webhooker/internal/globals"
|
||||
"sneak.berlin/go/webhooker/internal/healthcheck"
|
||||
"sneak.berlin/go/webhooker/internal/logger"
|
||||
"sneak.berlin/go/webhooker/internal/session"
|
||||
)
|
||||
|
||||
// nolint:revive // HandlersParams is a standard fx naming convention
|
||||
|
||||
@ -6,16 +6,16 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/internal/config"
|
||||
"git.eeqj.de/sneak/webhooker/internal/database"
|
||||
"git.eeqj.de/sneak/webhooker/internal/globals"
|
||||
"git.eeqj.de/sneak/webhooker/internal/healthcheck"
|
||||
"git.eeqj.de/sneak/webhooker/internal/logger"
|
||||
"git.eeqj.de/sneak/webhooker/internal/session"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/fx"
|
||||
"go.uber.org/fx/fxtest"
|
||||
"sneak.berlin/go/webhooker/internal/config"
|
||||
"sneak.berlin/go/webhooker/internal/database"
|
||||
"sneak.berlin/go/webhooker/internal/globals"
|
||||
"sneak.berlin/go/webhooker/internal/healthcheck"
|
||||
"sneak.berlin/go/webhooker/internal/logger"
|
||||
"sneak.berlin/go/webhooker/internal/session"
|
||||
)
|
||||
|
||||
func TestHandleIndex(t *testing.T) {
|
||||
|
||||
@ -5,7 +5,7 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/internal/database"
|
||||
"sneak.berlin/go/webhooker/internal/database"
|
||||
)
|
||||
|
||||
type IndexResponse struct {
|
||||
|
||||
@ -5,11 +5,11 @@ import (
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/internal/config"
|
||||
"git.eeqj.de/sneak/webhooker/internal/database"
|
||||
"git.eeqj.de/sneak/webhooker/internal/globals"
|
||||
"git.eeqj.de/sneak/webhooker/internal/logger"
|
||||
"go.uber.org/fx"
|
||||
"sneak.berlin/go/webhooker/internal/config"
|
||||
"sneak.berlin/go/webhooker/internal/database"
|
||||
"sneak.berlin/go/webhooker/internal/globals"
|
||||
"sneak.berlin/go/webhooker/internal/logger"
|
||||
)
|
||||
|
||||
// nolint:revive // HealthcheckParams is a standard fx naming convention
|
||||
|
||||
@ -6,8 +6,8 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/internal/globals"
|
||||
"go.uber.org/fx"
|
||||
"sneak.berlin/go/webhooker/internal/globals"
|
||||
)
|
||||
|
||||
// nolint:revive // LoggerParams is a standard fx naming convention
|
||||
|
||||
@ -3,8 +3,8 @@ package logger
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/internal/globals"
|
||||
"go.uber.org/fx/fxtest"
|
||||
"sneak.berlin/go/webhooker/internal/globals"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
|
||||
@ -6,9 +6,6 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/internal/config"
|
||||
"git.eeqj.de/sneak/webhooker/internal/globals"
|
||||
"git.eeqj.de/sneak/webhooker/internal/logger"
|
||||
basicauth "github.com/99designs/basicauth-go"
|
||||
"github.com/go-chi/chi/middleware"
|
||||
"github.com/go-chi/cors"
|
||||
@ -16,6 +13,9 @@ import (
|
||||
ghmm "github.com/slok/go-http-metrics/middleware"
|
||||
"github.com/slok/go-http-metrics/middleware/std"
|
||||
"go.uber.org/fx"
|
||||
"sneak.berlin/go/webhooker/internal/config"
|
||||
"sneak.berlin/go/webhooker/internal/globals"
|
||||
"sneak.berlin/go/webhooker/internal/logger"
|
||||
)
|
||||
|
||||
// nolint:revive // MiddlewareParams is a standard fx naming convention
|
||||
|
||||
@ -4,11 +4,11 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/static"
|
||||
sentryhttp "github.com/getsentry/sentry-go/http"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/chi/middleware"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"sneak.berlin/go/webhooker/static"
|
||||
)
|
||||
|
||||
func (s *Server) SetupRoutes() {
|
||||
@ -63,7 +63,7 @@ func (s *Server) SetupRoutes() {
|
||||
})
|
||||
|
||||
s.router.Get(
|
||||
"/.well-known/healthcheck.json",
|
||||
"/.well-known/healthcheck",
|
||||
s.h.HandleHealthCheck(),
|
||||
)
|
||||
|
||||
|
||||
@ -10,12 +10,12 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/internal/config"
|
||||
"git.eeqj.de/sneak/webhooker/internal/globals"
|
||||
"git.eeqj.de/sneak/webhooker/internal/handlers"
|
||||
"git.eeqj.de/sneak/webhooker/internal/logger"
|
||||
"git.eeqj.de/sneak/webhooker/internal/middleware"
|
||||
"go.uber.org/fx"
|
||||
"sneak.berlin/go/webhooker/internal/config"
|
||||
"sneak.berlin/go/webhooker/internal/globals"
|
||||
"sneak.berlin/go/webhooker/internal/handlers"
|
||||
"sneak.berlin/go/webhooker/internal/logger"
|
||||
"sneak.berlin/go/webhooker/internal/middleware"
|
||||
|
||||
"github.com/getsentry/sentry-go"
|
||||
"github.com/go-chi/chi"
|
||||
|
||||
@ -6,10 +6,10 @@ import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/internal/config"
|
||||
"git.eeqj.de/sneak/webhooker/internal/logger"
|
||||
"github.com/gorilla/sessions"
|
||||
"go.uber.org/fx"
|
||||
"sneak.berlin/go/webhooker/internal/config"
|
||||
"sneak.berlin/go/webhooker/internal/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// import "git.eeqj.de/sneak/webhooker/pkg/config"
|
||||
// import "sneak.berlin/go/webhooker/pkg/config"
|
||||
//
|
||||
// // Set the environment explicitly
|
||||
// config.SetEnvironment("prod")
|
||||
|
||||
@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/pkg/config"
|
||||
"github.com/spf13/afero"
|
||||
"sneak.berlin/go/webhooker/pkg/config"
|
||||
)
|
||||
|
||||
// ExampleSetFs demonstrates how to use an in-memory filesystem for testing
|
||||
|
||||
@ -5,7 +5,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"git.eeqj.de/sneak/webhooker/pkg/config"
|
||||
"sneak.berlin/go/webhooker/pkg/config"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
module git.eeqj.de/sneak/webhooker/pkg/config
|
||||
module sneak.berlin/go/webhooker/pkg/config
|
||||
|
||||
go 1.23.0
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user