Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesLegalLegal — Data Model

Legal — Data Model

Two tables. Defined in libs/db/src/lib/schema/legal.ts.

ColumnTypeNotes
iduuid PK
typelegal_document_type NOT NULLterms_of_use, privacy_policy, fitness_waiver, cookie_policy, acceptable_use
versionvarchar(20) NOT NULLSemver-ish string, e.g. '2.0.0'. Compared by published_at not by parsing this field
localevarchar(5) NOT NULLhe, en, ru
urltext NOT NULLCanonical URL on marketing site
published_attimestamptz NOT NULLSource of truth for “latest” ordering
created_attimestamptz NOT NULL DEFAULT now

Unique: (type, version, locale).

ColumnTypeNotes
iduuid PK
user_iduuid NOT NULLFK users(id) (no ON DELETE — see PII)
organization_iduuidFK organizations(id) nullable — audit context only; consent is platform-level
document_iduuid NOT NULLFK legal_documents(id)
consent_contextconsent_context NOT NULLowner_onboarding, member_onboarding, reconsent, profile_update
ip_addressvarchar(45)IPv6-capable
user_agenttextFull UA string
consented_attimestamptz NOT NULL DEFAULT now
revoked_attimestamptzNULL = active. No UI today

Index: (user_id, document_id).

Relationships

legal_documents 1 ─── * legal_consents users 1 ─── * legal_consents organizations 1 ─── * legal_consents (audit context, optional)

Multi-org isolation

Not org-scoped. Documents and consents are platform-level. The optional organization_id on a consent row is audit metadata only — it captures “which org context the user was in when they accepted” (e.g. signing up to a specific gym’s onboarding). It does not affect document selection.

PII handling

  • ip_address and user_agent are plaintext audit evidence.
  • No special encryption.
  • revoked_at exists for soft-revocation. No “right to be forgotten” cascade — deleting a user leaves legal_consents.user_id dangling because there’s no ON DELETE clause. Cleanup is a future ops concern.

Soft vs hard delete

  • Documents: never deleted by app code.
  • Consents: soft-revocable via revoked_at. Active rows have revoked_at IS NULL — every read filters on this.