mirror of
https://github.com/Dvorinka/Bookra.git
synced 2026-10-29 07:54:44 +00:00
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:
1 parent
e5cb9bd543
commit
d86cba61e3
18 files changed
+634
-28
No files matched your search
@@ -276,6 +276,7 @@ func (s *Service) Create(ctx context.Context, request domain.CreateBookingReques
|
||||
}
|
||||
|
||||
status := "confirmed"
|
||||
activityLabel := ""
|
||||
switch request.BookingMode {
|
||||
case "appointment":
|
||||
if request.ServiceID == nil || request.ClassSessionID != nil {
|
||||
@@ -288,6 +289,7 @@ func (s *Service) Create(ctx context.Context, request domain.CreateBookingReques
|
||||
if !ok {
|
||||
return domain.CreateBookingResponse{}, fmt.Errorf("%w: serviceId is not available for tenant", ErrInvalidBooking)
|
||||
}
|
||||
activityLabel = service.Name
|
||||
expectedDuration := time.Duration(service.DurationMinutes) * time.Minute
|
||||
if !startsAt.Add(expectedDuration).Equal(endsAt) {
|
||||
return domain.CreateBookingResponse{}, fmt.Errorf("%w: appointment duration must match service duration", ErrInvalidBooking)
|
||||
@@ -317,6 +319,7 @@ func (s *Service) Create(ctx context.Context, request domain.CreateBookingReques
|
||||
if !sameSecond(session.StartsAt, startsAt) || !sameSecond(session.EndsAt, endsAt) {
|
||||
return domain.CreateBookingResponse{}, fmt.Errorf("%w: class booking time must match class session", ErrInvalidBooking)
|
||||
}
|
||||
activityLabel = session.Title
|
||||
classBookings := countClassBookings(existing, *request.ClassSessionID)
|
||||
if session.Capacity > 0 && classBookings >= session.Capacity {
|
||||
status = "waitlisted"
|
||||
@@ -366,6 +369,17 @@ func (s *Service) Create(ctx context.Context, request domain.CreateBookingReques
|
||||
return domain.CreateBookingResponse{}, err
|
||||
}
|
||||
|
||||
// Audit feed — best-effort like confirmation emails.
|
||||
_ = s.repo.AppendActivityEvent(ctx, db.ActivityEventParams{
|
||||
TenantID: tenant.ID,
|
||||
ActorKind: "customer",
|
||||
ActorName: customerName,
|
||||
Action: "booking.created",
|
||||
EntityType: "booking",
|
||||
EntityID: &created.ID,
|
||||
Summary: customerName + " — " + activityLabel,
|
||||
})
|
||||
|
||||
// Send confirmation emails (async - don't fail booking if email fails)
|
||||
go s.sendBookingConfirmationEmails(tenant, created, request.ServiceID, request.LocationID, customerName, customerEmail, startsAt, endsAt)
|
||||
|
||||
|
||||
Reference in new issue
Block a user