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

Class Types — Data Model

Table: class_types in libs/db/src/lib/schema/scheduling.ts.

Columns

ColumnTypeNotes
iduuid PKdefaultRandom()
program_iduuid NOT NULLFK → programs.id. Org boundaryprograms.organization_id is the org.
namevarchar(255) NOT NULLDisplay name.
descriptiontextOptional long-form.
default_duration_minintUsed to suggest endsAt in the session creator.
default_capacityintDefault capacity for new sessions (overridable).
colorvarchar(7)Hex; renders calendar pill.
has_workoutbool NOT NULL default trueWhen false, schedule UX suppresses workout-attachment affordances (“Open Gym” pattern).
is_activebool NOT NULL default trueSoft-deactivate flag.
created_at / updated_attimestamptz
deleted_attimestamptzDefined on the column but never written by the service — remove sets is_active=false instead. TODO: verify whether any consumer reads deleted_at.

Indexes / constraints

No additional indexes declared in the schema file (only the PK). No UNIQUE constraints (multiple class types may share a name within an org).

Relations

  • program — one-to-one (mandatory parent).
  • classSessions — one-to-many.
  • dailyProgramming — one-to-many (daily_programming.class_type_id).

Lifecycle of a row

  1. CreateINSERT with is_active=true, has_workout=true default. Service validates the program belongs to the caller’s org.
  2. Update — partial PATCH; no field except program_id can change (program_id is intentionally omitted from UpdateClassTypeDto).
  3. DeactivateUPDATE … SET is_active=false. Historical references remain valid.

No row is ever hard-deleted by the service.

Multi-org isolation pattern

class_types has no direct organization_id column. Org-scoping pivots through the parent programs.organization_id. Every service method:

  1. Calls MembershipsService.requireMembership(orgId, clerkId) (403 if not a member).
  2. Joins / fetches the parent program and verifies program.organizationId === orgId (404 if mismatch).

Soft-delete vs hard-delete

Soft only, via is_active. The deleted_at column exists but is unused — kept for parity with sibling tables.