Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesClass TypesClass Types — Behavior

Class Types — Behavior

State

Class types do not have a status machine. They have a single boolean is_active:

StateMeaning
is_active=trueSurfaces in findAll, allowed as class_type_id for new sessions.
is_active=falseHidden from findAll. Existing class sessions still reference it — soft-deactivate, not cascade.

DELETE /class-types/:id performs update set is_active=false, never DELETE FROM. The row stays so historical sessions, bookings, and analytics keep their referential integrity.

Invariants

  • Program must belong to the same org as the caller’s membership. Create + update both verify program.organizationId === orgId before mutating (class-types.service.ts:33-42, :115-121).
  • Class type cannot be reassigned to another program — there is no programId field on UpdateClassTypeDto.
  • No hard delete — deactivation only. This is load-bearing for the schedule history.
  • Org isolation via the program — class types have no direct organization_id column.

Golden paths

Owner: add a new class

  1. Go to /dashboard/schedule → “Tracks” / class types tab.
  2. Click “Add class type”, pick parent program from a dropdown, name it, set defaults (60 min, capacity 20, color), toggle hasWorkout if it’s a no-program class.
  3. POST /organizations/:orgId/class-types returns the new row + program metadata.
  4. The class type appears in the create-session form.

Owner: deactivate

  1. Open class type; click “Delete”.
  2. DELETE /organizations/:orgId/class-types/:id.
  3. The class type disappears from findAll. Historical sessions still resolve classType (relational query returns the row regardless of is_active).

Edge cases & error states

ScenarioBehavior
Create with programId belonging to a different orgBadRequestException('Program not found in this organization')
Member or coach tries to create/update/deleteForbiddenException('Only owners and admins can …')
Get class type by id from another orgNotFoundException('Class type not found') (post-fetch org check)
Update with empty bodyReturns the row with updated_at bumped; all field updates are conditional on !== undefined.
Deactivate a class type with active future sessionsSessions remain. UI calendar still shows them. Booking still works. (TODO: confirm whether dashboard surfaces a warning.)

Side effects

None outside the row mutation itself. No events emitted, no notifications, no cascades.

Permissions

Actionowneradmincoachmember
List
Get by id
Create
Update
Deactivate

All endpoints require an active membership in the org; cross-org access fails at requireMembership (403) or the program.organizationId post-check (404).