refactor: rename Processor to Webhook and Webhook to Entrypoint

The top-level entity that groups entrypoints and targets is now called
Webhook (was Processor). The inbound URL endpoint entity is now called
Entrypoint (was Webhook). This rename affects database models, handler
comments, routes, and README documentation.

closes #12
This commit is contained in:
clawbot
2026-03-01 15:44:22 -08:00
committed by user
parent b5cf4c3d2f
commit 7bbe47b943
10 changed files with 63 additions and 63 deletions

View File

@@ -0,0 +1,14 @@
package database
// Entrypoint represents an inbound URL endpoint that feeds into a webhook
type Entrypoint struct {
BaseModel
WebhookID string `gorm:"type:uuid;not null" json:"webhook_id"`
Path string `gorm:"uniqueIndex;not null" json:"path"` // URL path for this entrypoint
Description string `json:"description"`
Active bool `gorm:"default:true" json:"active"`
// Relations
Webhook Webhook `json:"webhook,omitempty"`
}

View File

@@ -1,11 +1,11 @@
package database package database
// Event represents a webhook event // Event represents a captured webhook event
type Event struct { type Event struct {
BaseModel BaseModel
ProcessorID string `gorm:"type:uuid;not null" json:"processor_id"`
WebhookID string `gorm:"type:uuid;not null" json:"webhook_id"` WebhookID string `gorm:"type:uuid;not null" json:"webhook_id"`
EntrypointID string `gorm:"type:uuid;not null" json:"entrypoint_id"`
// Request data // Request data
Method string `gorm:"not null" json:"method"` Method string `gorm:"not null" json:"method"`
@@ -14,7 +14,7 @@ type Event struct {
ContentType string `json:"content_type"` ContentType string `json:"content_type"`
// Relations // Relations
Processor Processor `json:"processor,omitempty"`
Webhook Webhook `json:"webhook,omitempty"` Webhook Webhook `json:"webhook,omitempty"`
Entrypoint Entrypoint `json:"entrypoint,omitempty"`
Deliveries []Delivery `json:"deliveries,omitempty"` Deliveries []Delivery `json:"deliveries,omitempty"`
} }

View File

@@ -1,16 +0,0 @@
package database
// Processor represents an event processor
type Processor struct {
BaseModel
UserID string `gorm:"type:uuid;not null" json:"user_id"`
Name string `gorm:"not null" json:"name"`
Description string `json:"description"`
RetentionDays int `gorm:"default:30" json:"retention_days"` // Days to retain events
// Relations
User User `json:"user,omitempty"`
Webhooks []Webhook `json:"webhooks,omitempty"`
Targets []Target `json:"targets,omitempty"`
}

View File

@@ -10,11 +10,11 @@ const (
TargetTypeLog TargetType = "log" TargetTypeLog TargetType = "log"
) )
// Target represents a delivery target for a processor // Target represents a delivery target for a webhook
type Target struct { type Target struct {
BaseModel BaseModel
ProcessorID string `gorm:"type:uuid;not null" json:"processor_id"` WebhookID string `gorm:"type:uuid;not null" json:"webhook_id"`
Name string `gorm:"not null" json:"name"` Name string `gorm:"not null" json:"name"`
Type TargetType `gorm:"not null" json:"type"` Type TargetType `gorm:"not null" json:"type"`
Active bool `gorm:"default:true" json:"active"` Active bool `gorm:"default:true" json:"active"`
@@ -27,6 +27,6 @@ type Target struct {
MaxQueueSize int `json:"max_queue_size,omitempty"` MaxQueueSize int `json:"max_queue_size,omitempty"`
// Relations // Relations
Processor Processor `json:"processor,omitempty"` Webhook Webhook `json:"webhook,omitempty"`
Deliveries []Delivery `json:"deliveries,omitempty"` Deliveries []Delivery `json:"deliveries,omitempty"`
} }

View File

@@ -8,6 +8,6 @@ type User struct {
Password string `gorm:"not null" json:"-"` // Argon2 hashed Password string `gorm:"not null" json:"-"` // Argon2 hashed
// Relations // Relations
Processors []Processor `json:"processors,omitempty"` Webhooks []Webhook `json:"webhooks,omitempty"`
APIKeys []APIKey `json:"api_keys,omitempty"` APIKeys []APIKey `json:"api_keys,omitempty"`
} }

View File

@@ -1,14 +1,16 @@
package database package database
// Webhook represents a webhook endpoint that feeds into a processor // Webhook represents a webhook processing unit that groups entrypoints and targets
type Webhook struct { type Webhook struct {
BaseModel BaseModel
ProcessorID string `gorm:"type:uuid;not null" json:"processor_id"` UserID string `gorm:"type:uuid;not null" json:"user_id"`
Path string `gorm:"uniqueIndex;not null" json:"path"` // URL path for this webhook Name string `gorm:"not null" json:"name"`
Description string `json:"description"` Description string `json:"description"`
Active bool `gorm:"default:true" json:"active"` RetentionDays int `gorm:"default:30" json:"retention_days"` // Days to retain events
// Relations // Relations
Processor Processor `json:"processor,omitempty"` User User `json:"user,omitempty"`
Entrypoints []Entrypoint `json:"entrypoints,omitempty"`
Targets []Target `json:"targets,omitempty"`
} }

View File

@@ -5,8 +5,8 @@ func (d *Database) Migrate() error {
return d.db.AutoMigrate( return d.db.AutoMigrate(
&User{}, &User{},
&APIKey{}, &APIKey{},
&Processor{},
&Webhook{}, &Webhook{},
&Entrypoint{},
&Target{}, &Target{},
&Event{}, &Event{},
&Delivery{}, &Delivery{},

View File

@@ -4,66 +4,66 @@ import (
"net/http" "net/http"
) )
// HandleSourceList shows a list of user's webhook sources // HandleSourceList shows a list of user's webhooks
func (h *Handlers) HandleSourceList() http.HandlerFunc { func (h *Handlers) HandleSourceList() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// TODO: Implement source list page // TODO: Implement webhook list page
http.Error(w, "Not implemented", http.StatusNotImplemented) http.Error(w, "Not implemented", http.StatusNotImplemented)
} }
} }
// HandleSourceCreate shows the form to create a new webhook source // HandleSourceCreate shows the form to create a new webhook
func (h *Handlers) HandleSourceCreate() http.HandlerFunc { func (h *Handlers) HandleSourceCreate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// TODO: Implement source creation form // TODO: Implement webhook creation form
http.Error(w, "Not implemented", http.StatusNotImplemented) http.Error(w, "Not implemented", http.StatusNotImplemented)
} }
} }
// HandleSourceCreateSubmit handles the source creation form submission // HandleSourceCreateSubmit handles the webhook creation form submission
func (h *Handlers) HandleSourceCreateSubmit() http.HandlerFunc { func (h *Handlers) HandleSourceCreateSubmit() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// TODO: Implement source creation logic // TODO: Implement webhook creation logic
http.Error(w, "Not implemented", http.StatusNotImplemented) http.Error(w, "Not implemented", http.StatusNotImplemented)
} }
} }
// HandleSourceDetail shows details for a specific webhook source // HandleSourceDetail shows details for a specific webhook
func (h *Handlers) HandleSourceDetail() http.HandlerFunc { func (h *Handlers) HandleSourceDetail() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// TODO: Implement source detail page // TODO: Implement webhook detail page
http.Error(w, "Not implemented", http.StatusNotImplemented) http.Error(w, "Not implemented", http.StatusNotImplemented)
} }
} }
// HandleSourceEdit shows the form to edit a webhook source // HandleSourceEdit shows the form to edit a webhook
func (h *Handlers) HandleSourceEdit() http.HandlerFunc { func (h *Handlers) HandleSourceEdit() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// TODO: Implement source edit form // TODO: Implement webhook edit form
http.Error(w, "Not implemented", http.StatusNotImplemented) http.Error(w, "Not implemented", http.StatusNotImplemented)
} }
} }
// HandleSourceEditSubmit handles the source edit form submission // HandleSourceEditSubmit handles the webhook edit form submission
func (h *Handlers) HandleSourceEditSubmit() http.HandlerFunc { func (h *Handlers) HandleSourceEditSubmit() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// TODO: Implement source update logic // TODO: Implement webhook update logic
http.Error(w, "Not implemented", http.StatusNotImplemented) http.Error(w, "Not implemented", http.StatusNotImplemented)
} }
} }
// HandleSourceDelete handles webhook source deletion // HandleSourceDelete handles webhook deletion
func (h *Handlers) HandleSourceDelete() http.HandlerFunc { func (h *Handlers) HandleSourceDelete() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// TODO: Implement source deletion logic // TODO: Implement webhook deletion logic
http.Error(w, "Not implemented", http.StatusNotImplemented) http.Error(w, "Not implemented", http.StatusNotImplemented)
} }
} }
// HandleSourceLogs shows the request/response logs for a webhook source // HandleSourceLogs shows the request/response logs for a webhook
func (h *Handlers) HandleSourceLogs() http.HandlerFunc { func (h *Handlers) HandleSourceLogs() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// TODO: Implement source logs page // TODO: Implement webhook logs page
http.Error(w, "Not implemented", http.StatusNotImplemented) http.Error(w, "Not implemented", http.StatusNotImplemented)
} }
} }

View File

@@ -6,19 +6,19 @@ import (
"github.com/go-chi/chi" "github.com/go-chi/chi"
) )
// HandleWebhook handles incoming webhook requests // HandleWebhook handles incoming webhook requests at entrypoint URLs
func (h *Handlers) HandleWebhook() http.HandlerFunc { func (h *Handlers) HandleWebhook() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
// Get webhook UUID from URL // Get entrypoint UUID from URL
webhookUUID := chi.URLParam(r, "uuid") entrypointUUID := chi.URLParam(r, "uuid")
if webhookUUID == "" { if entrypointUUID == "" {
http.NotFound(w, r) http.NotFound(w, r)
return return
} }
// Log the incoming webhook request // Log the incoming webhook request
h.log.Info("webhook request received", h.log.Info("webhook request received",
"uuid", webhookUUID, "entrypoint_uuid", entrypointUUID,
"method", r.Method, "method", r.Method,
"remote_addr", r.RemoteAddr, "remote_addr", r.RemoteAddr,
"user_agent", r.UserAgent(), "user_agent", r.UserAgent(),
@@ -32,7 +32,7 @@ func (h *Handlers) HandleWebhook() http.HandlerFunc {
} }
// TODO: Implement webhook handling logic // TODO: Implement webhook handling logic
// For now, return "unimplemented" for all webhook POST requests // Look up entrypoint by UUID, find parent webhook, fan out to targets
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
_, err := w.Write([]byte("unimplemented")) _, err := w.Write([]byte("unimplemented"))
if err != nil { if err != nil {

View File

@@ -90,23 +90,23 @@ func (s *Server) SetupRoutes() {
r.Get("/", s.h.HandleProfile()) r.Get("/", s.h.HandleProfile())
}) })
// Webhook source management routes (require authentication) // Webhook management routes (require authentication)
s.router.Route("/sources", func(r chi.Router) { s.router.Route("/sources", func(r chi.Router) {
// TODO: Add authentication middleware here // TODO: Add authentication middleware here
r.Get("/", s.h.HandleSourceList()) // List all sources r.Get("/", s.h.HandleSourceList()) // List all webhooks
r.Get("/new", s.h.HandleSourceCreate()) // Show create form r.Get("/new", s.h.HandleSourceCreate()) // Show create form
r.Post("/new", s.h.HandleSourceCreateSubmit()) // Handle create submission r.Post("/new", s.h.HandleSourceCreateSubmit()) // Handle create submission
}) })
s.router.Route("/source/{sourceID}", func(r chi.Router) { s.router.Route("/source/{sourceID}", func(r chi.Router) {
// TODO: Add authentication middleware here // TODO: Add authentication middleware here
r.Get("/", s.h.HandleSourceDetail()) // View source details r.Get("/", s.h.HandleSourceDetail()) // View webhook details
r.Get("/edit", s.h.HandleSourceEdit()) // Show edit form r.Get("/edit", s.h.HandleSourceEdit()) // Show edit form
r.Post("/edit", s.h.HandleSourceEditSubmit()) // Handle edit submission r.Post("/edit", s.h.HandleSourceEditSubmit()) // Handle edit submission
r.Post("/delete", s.h.HandleSourceDelete()) // Delete source r.Post("/delete", s.h.HandleSourceDelete()) // Delete webhook
r.Get("/logs", s.h.HandleSourceLogs()) // View source logs r.Get("/logs", s.h.HandleSourceLogs()) // View webhook logs
}) })
// Webhook endpoint - accepts all HTTP methods // Entrypoint endpoint - accepts incoming webhook POST requests
s.router.HandleFunc("/webhook/{uuid}", s.h.HandleWebhook()) s.router.HandleFunc("/webhook/{uuid}", s.h.HandleWebhook())
} }