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

Class Types — Code Map

API

FilePurpose
apps/api/src/class-types/class-types.module.tsWires controller + service; imports MembershipsModule.
apps/api/src/class-types/class-types.controller.tsRoutes; toResponse mapper to ClassTypeResponse (@taikan/shared).
apps/api/src/class-types/class-types.service.tsCRUD; depends on MembershipsService.requireMembership for auth, raw programs query for org-belonging check, and an org check on defaultLocationId.
apps/api/src/class-types/dto/create-class-type.dto.tsprogramId, name, description?, defaultDurationMin?, defaultCapacity?, defaultLocationId? (uuid or null), color?, hasWorkout?, countsTowardQuota?.
apps/api/src/class-types/dto/update-class-type.dto.tsPartialType minus programId.

Routes (prefix organizations/:orgId/class-types)

MethodPathHandlerNotes
POST/createowner/admin
GET/listany member; optional ?programId= filter
GET/:idgetByIdany member
PATCH/:idupdateowner/admin
DELETE/:idremove (deactivate)owner/admin

Web

  • apps/web/src/components/overview/schedule/class-type-dialog.tsx — create/edit dialog, including the default space picker and the “Deducts an entry from the member’s plan” switch (ct-counts-toward-quota). Opened from apps/web/src/components/overview/programming/program-class-types-tab.tsx, which badges open classes (classTypes.noQuotaBadge).
  • apps/web/src/app/[lang]/(protected)/dashboard/schedule/page.tsx and its sub-tabs render the class types ribbon.
  • i18n keys: schedule.classTypes*, schedule.classTypeSheet* (countsTowardQuotaLabel/countsTowardQuotaHelper), classTypes.noQuotaBadge in libs/shared/src/lib/i18n/dictionaries/{en,he,ru}.json.

Where countsTowardQuota is read

FileRole
apps/api/src/bookings/bookings.service.tsbookForSubject reads it with the session shape; an open session skips plan resolution and the plan-required/presale gate rules (assertBillingAllowsBooking’s quotaExempt), and the booking is written with subscription_id = NULL.
apps/api/src/class-sessions/class-sessions.service.tstoResponse overrides bookingEligibility to eligible/no plans on an open session and sends classType.countsTowardQuota; bookingPreview reports decidedBy.layer = 'quota_exempt'.
apps/api/src/trials/trial-seats.service.tsA converted lead’s trial seat on an open session gets no plan attached or charged.
apps/web/src/components/member/schedule/session-detail-drawer.tsxShows schedule.memberBooking.openSessionNote on an open session.
apps/web/src/components/overview/members/member-why-preview.tsxRenders the quota_exempt layer (members.whyPreview.decidedBy.quota_exempt).

DB tables

TableUsed as
class_typesOwned.
programsParent FK (class_types.program_id). Org boundary lives here.
class_sessionsChild; references class_type_id.
locationsclass_types.default_location_id → locations.id (ON DELETE SET NULL).
daily_programmingKeys by class_type_id + date.

Shared schemas

  • libs/shared/src/lib/schemas/scheduling.schema.ts — ClassTypeResponse shape:
    { id, programId, name, description, defaultDurationMin, defaultCapacity, defaultLocationId, color, hasWorkout, countsTowardQuota, isActive, createdAt, program: { id, name, deliveryMode } }

Tests

  • class-types.audit.unit.spec.ts — the remove (deactivate) audit trail.
  • class-types.find-all.unit.spec.ts — findAll’s SQL scoping: org isolation via the programs join, and the optional programId filter. Most other CRUD is exercised indirectly through scheduling specs.