feat: implement core webhook engine, delivery system, and management UI (Phase 2)
All checks were successful
check / check (push) Successful in 1m49s
All checks were successful
check / check (push) Successful in 1m49s
- Webhook reception handler: look up entrypoint by UUID, verify active,
capture full HTTP request (method, headers, body, content-type), create
Event record, queue Delivery records for each active Target, return 200 OK.
Handles edge cases: unknown UUID → 404, inactive → 410, oversized → 413.
- Delivery engine (internal/delivery): fx-managed background goroutine that
polls for pending/retrying deliveries and dispatches to target type handlers.
Graceful shutdown via context cancellation.
- Target type implementations:
- HTTP: fire-and-forget POST with original headers forwarding
- Retry: exponential backoff (1s, 2s, 4s...) up to max_retries
- Database: immediate success (event already stored)
- Log: slog output with event details
- Webhook management pages with Tailwind CSS + Alpine.js:
- List (/sources): webhooks with entrypoint/target/event counts
- Create (/sources/new): form with auto-created default entrypoint
- Detail (/source/{id}): config, entrypoints, targets, recent events
- Edit (/source/{id}/edit): name, description, retention_days
- Delete (/source/{id}/delete): soft-delete with child records
- Add Entrypoint (/source/{id}/entrypoints): inline form
- Add Target (/source/{id}/targets): type-aware form
- Event Log (/source/{id}/logs): paginated with delivery status
- Updated README: marked completed items, updated naming conventions
table, added delivery engine to package layout and DI docs, updated
column names to reflect entity rename.
- Rebuilt Tailwind CSS for new template classes.
Part of: #15
This commit is contained in:
@@ -100,11 +100,13 @@ func (s *Server) SetupRoutes() {
|
||||
|
||||
s.router.Route("/source/{sourceID}", func(r chi.Router) {
|
||||
r.Use(s.mw.RequireAuth())
|
||||
r.Get("/", s.h.HandleSourceDetail()) // View webhook details
|
||||
r.Get("/edit", s.h.HandleSourceEdit()) // Show edit form
|
||||
r.Post("/edit", s.h.HandleSourceEditSubmit()) // Handle edit submission
|
||||
r.Post("/delete", s.h.HandleSourceDelete()) // Delete webhook
|
||||
r.Get("/logs", s.h.HandleSourceLogs()) // View webhook logs
|
||||
r.Get("/", s.h.HandleSourceDetail()) // View webhook details
|
||||
r.Get("/edit", s.h.HandleSourceEdit()) // Show edit form
|
||||
r.Post("/edit", s.h.HandleSourceEditSubmit()) // Handle edit submission
|
||||
r.Post("/delete", s.h.HandleSourceDelete()) // Delete webhook
|
||||
r.Get("/logs", s.h.HandleSourceLogs()) // View webhook logs
|
||||
r.Post("/entrypoints", s.h.HandleEntrypointCreate()) // Add entrypoint
|
||||
r.Post("/targets", s.h.HandleTargetCreate()) // Add target
|
||||
})
|
||||
|
||||
// Entrypoint endpoint - accepts incoming webhook POST requests
|
||||
|
||||
Reference in New Issue
Block a user