Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesMetric SetsMetric Sets — Data Model

Metric Sets — Data Model

Schema: libs/db/src/lib/schema/metric-sets.ts.

metric_definitions (global catalogue)

ColumnTypeNotes
iduuid PK
slugvarchar(100) UNIQUEMachine identifier (e.g. back_squat_1rm)
name_i18njsonb NOT NULL{ en: "1RM Back Squat", he: "1RM סקוואט", ru: "1ПМ присед" }
unitmetric_unit NOT NULLkg, lb, %, seconds, …
kindmetric_kind NOT NULLone_rep_max, time, distance, body_comp, …
descriptiontext

Global (not org-scoped) — same vocabulary across the platform.

metric_sets

ColumnTypeNotes
iduuid PK
namevarchar(255) NOT NULL
member_user_iduuidFK users(id) CASCADE — set if owned by a member
workout_iduuidFK workouts(id) CASCADE — set if owned by a workout
organization_iduuidFK organizations(id) CASCADE — set if org-owned

Constraints:

  • metric_sets_owner_exclusive_chk — exactly one of the three owner FKs is non-null.

Indexes (all partial WHERE owner field IS NOT NULL):

  • metric_sets_member_idx on member_user_id.
  • metric_sets_workout_idx on workout_id.
  • metric_sets_org_idx on organization_id.

metric_set_definitions (junction)

ColumnTypeNotes
set_iduuid NOT NULLFK CASCADE
definition_iduuid NOT NULLFK RESTRICT (can’t delete a definition while still referenced)
sort_orderint NOT NULL DEFAULT 0

PK: (set_id, definition_id).

member_metrics (recorded values)

ColumnTypeNotes
iduuid PK
member_iduuid NOT NULLFK users(id). NB: column is on users.id, not memberships.id — values follow the person, not their gym tenure
definition_iduuid NOT NULLFK metric_definitions(id)
valuenumeric(14,4) NOT NULL
unitmetric_unit NOT NULL
recorded_attimestamptz NOT NULL DEFAULT now
sourcevarchar(50)e.g. coach_input, self_report, workout_result

Indexes:

  • member_metrics_member_def_recorded_idx on (member_id, definition_id, recorded_at DESC) — hot path for “latest value”.
  • member_metrics_definition_idx on (definition_id, recorded_at DESC) — “everyone’s most recent 1RM”.

Multi-org isolation

  • metric_definitions is global — same back_squat_1rm slug across all gyms.
  • metric_sets is owner-scoped (org / member / workout). Member-owned and member metrics follow the user across orgs (data lives at user-id, not membership-id).
  • Resolution endpoint: org-scoped by route, but member_metrics is fetched by user-id — staff in org A could in principle see a member’s metrics they recorded in org B. Cross-org leak risk worth a security review.

Soft / hard delete

  • No soft-delete columns. Hard delete only via cascade.