feat: HA scheduler leadership + templated email log

HA scheduler: the job scheduler and alert evaluator hold session-scoped
PostgreSQL advisory locks on pinned pool connections — replicas scan for
due work exactly once, failover verified live with two replicas. Manual
and hook-triggered runs stay available on any replica.

Email surface: mailer renders registered templates (invitation); every
send is logged to core.email_log with status and error text. New
GET /projects/:id/emails endpoint; Members page shows an Email log card.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Tomas DvorakandDevin committed 2026-09-24 19:27:06 +02:00
1 parent 45a1621909
commit f747b33b46
24 files changed
+669 -16

No files matched your search

+20
View File
@@ -4,6 +4,7 @@ import (
"errors"
"io"
"net/http"
"strconv"
"strings"
"github.com/gin-gonic/gin"
@@ -80,6 +81,25 @@ func (h *HTTPHandler) deleteInboundHook(c *gin.Context) {
c.Status(http.StatusNoContent)
}
func (h *HTTPHandler) listEmailLog(c *gin.Context) {
actor, projectID, ok := h.actorAndProject(c)
if !ok {
return
}
var limit int64
if raw := c.Query("limit"); raw != "" {
if n, err := strconv.ParseInt(raw, 10, 64); err == nil {
limit = n
}
}
result, err := h.Platform.ListEmailLog(c.Request.Context(), actor, projectID, limit)
if err != nil {
h.handleError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{"items": result})
}
// receiveInboundHook is the public ingest endpoint — the URL token is the
// credential, so no actor is required.
func (h *HTTPHandler) receiveInboundHook(c *gin.Context) {