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

+85
View File
@@ -1311,6 +1311,38 @@ paths:
"404":
description: Template or location not found
/v1/catalog/class-sessions/{sessionID}:
patch:
tags: [Catalog]
operationId: updateClassSession
summary: Patch a class session (currently capacity only)
security:
- bearerAuth: []
parameters:
- in: path
name: sessionID
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateClassSessionRequest"
responses:
"200":
description: Updated class session
content:
application/json:
schema:
$ref: "#/components/schemas/ClassSession"
"400":
description: Invalid request
"404":
description: Class session not found
"409":
description: Capacity below confirmed bookings (pass allowOverCapacity to force)
delete:
tags: [Catalog]
operationId: deleteClassSession
@@ -1938,6 +1970,36 @@ paths:
description: Monthly SMS invoices generated
"401":
description: Unauthorized
/v1/internal/jobs/reports/dispatch:
post:
tags: [Jobs]
operationId: dispatchReportDigests
summary: Email each tenant owner a trailing-window business digest
security:
- jobRunnerKey: []
parameters:
- in: query
name: days
schema:
type: integer
default: 7
maximum: 365
description: Trailing window length in days
- in: query
name: tenantId
schema:
type: string
format: uuid
description: Scope the run to a single tenant
responses:
"200":
description: Digests dispatched
content:
application/json:
schema:
$ref: "#/components/schemas/DispatchReportDigestsResponse"
"401":
description: Unauthorized
components:
securitySchemes:
bearerAuth:
@@ -3083,6 +3145,17 @@ components:
startsLocal:
type: string
description: Tenant-local start time, HH:MM
UpdateClassSessionRequest:
type: object
required: [capacity]
properties:
capacity:
type: integer
minimum: 1
maximum: 500
allowOverCapacity:
type: boolean
description: Permit shrinking below the confirmed seat count
UpdateClassScheduleRequest:
type: object
description: >-
@@ -3264,3 +3337,15 @@ components:
type: integer
skippedCount:
type: integer
DispatchReportDigestsResponse:
type: object
required: [tenantCount, sentCount, skippedCount, failedCount]
properties:
tenantCount:
type: integer
sentCount:
type: integer
skippedCount:
type: integer
failedCount:
type: integer