feat(activity): per-tenant audit feed in notification dropdown

activity_events records booking lifecycle transitions with the actor
behind each change — staff (dashboard), customer (self-service), or
system (auto-promotion). The notification dropdown leads with the real
feed instead of derived recent-booking guesses.

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-18 16:06:13 +02:00
1 parent e5cb9bd543
commit d86cba61e3
18 files changed
+634 -28

No files matched your search

+16
View File
@@ -11,6 +11,7 @@ import (
"strings"
"time"
"bookra/apps/backend/internal/activity"
"bookra/apps/backend/internal/admin"
"bookra/apps/backend/internal/auth"
"bookra/apps/backend/internal/billing"
@@ -57,6 +58,7 @@ func NewServer(cfg config.Config, pools *db.Pools) (*Server, error) {
billingService := billing.NewService(cfg, repository)
catalogService := catalog.NewService(repository, billingService, notificationService)
calendarService := calendar.NewService(repository)
activityService := activity.NewService(repository)
authService := auth.NewService(repository, cfg.AuthJWTSecret)
adminService := admin.NewService(repository, cfg.AdminEmail, cfg.AdminKey)
smsService := sms.NewService(cfg, repository)
@@ -1277,6 +1279,20 @@ func NewServer(cfg config.Config, pools *db.Pools) (*Server, error) {
c.JSON(http.StatusOK, gin.H{"token": token, "feedPath": "/v1/public/calendar/" + token + ".ics"})
})
protected.GET("/activity", func(c *gin.Context) {
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "50"))
response, err := activityService.List(c.Request.Context(), auth.PrincipalFromContext(c), limit)
if err != nil {
status := http.StatusInternalServerError
if errors.Is(err, activity.ErrTenantMembership) {
status = http.StatusNotFound
}
c.JSON(status, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, response)
})
protected.GET("/billing/subscription", func(c *gin.Context) {
response, err := billingService.GetSubscription(c.Request.Context(), auth.PrincipalFromContext(c))
if err != nil {