feat: scheduled report digests + per-session capacity (M33)

POST /v1/internal/jobs/reports/dispatch emails each tenant owner a
trailing-window digest (bookings, revenue, per-service and per-staff
breakdown) localized to the tenant locale; zero-activity tenants are
skipped. Metrics cores extracted to tenant-scoped variants so the job
needs no principal.

PATCH /v1/catalog/class-sessions/:id sets a session's seat count with
a confirmed-bookings floor — shrinking below it needs allowOverCapacity,
matching the waitlist-promotion convention. Session rows gain an inline
capacity editor with an overbook confirm state.

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-22 21:29:44 +02:00
1 parent e6f1ec38a4
commit e680e0c2b8
14 files changed
+808 -10

No files matched your search

+17
View File
@@ -263,6 +263,15 @@ type DispatchReminderJobsResponse struct {
SkippedCount int `json:"skippedCount"`
}
// DispatchReportDigestsResponse summarizes one run of the scheduled digest
// job: how many tenants were considered and how the sends resolved.
type DispatchReportDigestsResponse struct {
TenantCount int `json:"tenantCount"`
SentCount int `json:"sentCount"`
SkippedCount int `json:"skippedCount"`
FailedCount int `json:"failedCount"`
}
// ============================================
// LOCATION / ZONE MODELS
// ============================================
@@ -470,6 +479,14 @@ type CreateClassSessionRequest struct {
Capacity *int `json:"capacity,omitempty"`
}
// UpdateClassSessionRequest patches a single session. Capacity is the only
// staff-editable field; shrinking below the confirmed seat count needs
// AllowOverCapacity (same convention as promoting onto a full session).
type UpdateClassSessionRequest struct {
Capacity *int `json:"capacity"`
AllowOverCapacity bool `json:"allowOverCapacity,omitempty"`
}
// ClassSchedule is a weekly recurring rule for a class template. Concrete
// sessions are materialized for a rolling horizon; DayOfWeek follows Go's
// time.Weekday (Sunday=0) and StartsLocal is an "HH:MM" tenant-local time.