Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesLegalLegal Documents (TOS, Privacy, Waivers)

Legal Documents (TOS, Privacy, Waivers)

Linear epic: Legal compliance (TOS/Privacy/Cookie/Waiver acceptance) Status: Shipped and in production. Last reviewed: 2026-05-28

What

Platform-level legal documents (Terms of Use, Privacy Policy, Cookie Policy, Acceptable Use, Fitness Waiver) and the per-user consent ledger that records which version each user accepted, when, from what IP, with which user-agent, and in what context (signup, reconsent, profile edit).

Distinct from compliance forms (see ../forms/):

AspectLegal documentsCompliance forms
OwnerFitKit platformEach org / gym
AudienceEvery userOrg members
StorageURL pointer + consent ledgerPDF in R2 + signature artefact
Localeper-locale rowsper-template locale field
OutputA legal_consents audit rowA signed PDF + audit row
Israeli regulator surfacePrivacy / consumer lawSports Promotion Law

Why

  • Israeli Privacy Protection Law + GDPR-equivalent require recorded, version-tied consent.
  • Reconsent when documents change (the user MUST re-accept a new TOS version before continued use).
  • The fitness waiver is a per-user platform-level waiver complementing the per-gym health_declaration compliance form.

Personas

PersonaSurfaceCapabilities
Any usersign-up flow + legal-acceptance-form.tsxRead documents, check boxes, accept; recorded with IP/UA/context
Returning user with outdated consentReconsent prompt at app entryAccept the new version
Org owner during onboardingInitial signup wizardAccept TOS + privacy + waiver
All usersProfile / settingsView consent status (per type), see version they accepted, dates

Capabilities

  • Document catalog (legal_documents) — versioned by (type, version, locale) unique key. published_at orders versions. URL field points to the marketing-site canonical (https://fitkit.fit/{slug}).
  • Consent ledger (legal_consents) — append-only per user × document. Soft-revocable via revoked_at (no UI today). Records ip_address, user_agent, consent_context, organization_id (audit trail).
  • Current-version resolverLegalService.getLatestDocuments(locale) returns one row per type, latest published_at (deterministic tiebreak on id).
  • Consent statusgetConsentStatus(userId) returns per-type { requiresReconsent, isCurrentVersion, consentedAt }.
  • GateshasRequiredConsents(userId) blocks app access until TOS + privacy + fitness waiver are accepted.
  • Idempotent recordrecordConsent skips documents the user already has an active consent for.

Capabilities (gaps)

GapTracking
Revoke consent UI (the column exists; no API surface)not tracked
Cookie consent banner (cookie_policy type exists; banner not implemented)not tracked
Region-aware document selection (always picks latest globally)not tracked
Audit log integration once FIT-20 landsFIT-20
  • Users / authdocs/features/users-auth/. Consent gating happens after Clerk sign-in.
  • Onboardingdocs/features/onboarding/. The acceptance form is embedded in the signup wizard.
  • Compliance forms../forms/. Different domain; do not confuse the two during QA.
  • Marketing site — hosts the canonical document URLs (fitkit.fit/{slug}).

Source code anchor

  • API: apps/api/src/legal/legal.{service,controller,module}.ts + dto/record-consent.dto.ts
  • DB schema: libs/db/src/lib/schema/legal.ts
  • Shared: libs/shared/src/lib/schemas/legal.schema.ts
  • Web component: apps/web/src/components/legal/legal-acceptance-form.tsx
  • Marketing fetch helper: apps/web/src/app/api/legal-document/route.ts

See behavior.md for state and qa-plan.md for tests.