Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesLegalLegal — Code Map

Legal — Code Map

API

FileRole
apps/api/src/legal/legal.module.tsImports UsersModule; provides and exports LegalService for consent recording/status
apps/api/src/legal/legal.controller.tsPublic GET /legal/documents; authenticated POST /legal/consents; GET /legal/consents/status?organizationId=… adds server-resolved isRequired and organizationId per row
apps/api/src/legal/legal.service.tsResolves current localized documents, records exact-version evidence, deduplicates external acknowledgement by organization, and returns version/scoped consent status
apps/api/src/legal/dto/record-consent.dto.tsValidates { types: LegalDocumentType[], context, organizationId?, locale? }
apps/api/src/users/users.service.tsgetLegalRequirements(userId, organizationId?) returns { types, organizationId } for the selected role: member privacy/health/member terms, owner platform Terms, or no requirements for admins/coaches until staff-specific terms exist. Pending-only member onboarding can add organization-scoped external acknowledgement; active-member backstop never does. getMissingMemberJoinLegalDocumentTypes keeps member invitations pending until required consent; staff creation does not validate or record member acceptance
apps/api/src/users/users.controller.ts/users/me?organizationId=… uses the same selected-org resolution as web: valid explicit org, then membership role priority; stale/omitted selections fall back
apps/api/src/join/join.service.tsPublic resolve returns required requiredLegalDocumentTypes; invitation request and authenticated direct accept independently resolve member terms and server payment configuration; reject missing acceptance before membership/invite mutation and record consent
apps/api/src/testing/testing.service.tsseedBase publishes the en base documents and records role-specific consent for owner and member personas; coaches have no required document until staff-specific terms exist, and the new-user owner consents inside onboarding. Without published documents the gate treats every required type as owed and affected e2e personas land on /accept-terms
apps/api/src/join/join.controller.tsJoin resolve, invite request, and authenticated direct-accept endpoints

DB

FileRole
libs/db/src/lib/schema/legal.tslegal_documents, legal_consents + relations
libs/db/src/lib/schema/enums.tslegal_document_type (7 values, including member_terms and external_payment_acknowledgement), consent_context (4 values)
libs/db/drizzle/0125_needy_zuras.sqlTransactional enum replacement plus three-locale publication of member terms and external-payment acknowledgement
libs/db/drizzle/0127_legal_document_locales.sqlAdds missing English/Russian publications for existing required documents and reconstructs only the privacy/fitness rows omitted from proven unified member-onboarding acceptance
libs/db/drizzle/meta/{_journal.json,0127_snapshot.json}Registers the custom data migration after the schema migrations

Shared

FileRole
libs/shared/src/lib/schemas/legal.schema.tsLegalDocumentType, ConsentContext, exact-version consent response shapes including server isRequired and resolved organizationId
libs/shared/src/lib/schemas/join-link.schema.tsRequired PublicJoinInfo.requiredLegalDocumentTypes; invite acceptance booleans/locale and independent analytics choice

Web

FileRole
apps/web/src/components/legal/legal-acceptance-form.tsxReusable acceptance dialog. Modes: standalone (with submit) or embedded (parent controls; reports tick state through the optional onAcceptedChange(accepted) and calls onAccepted when all boxes are ticked, used by the onboarding setup sheet). Links out to usetaikan.com/{slug} for full document text
apps/web/src/app/api/legal-document/route.tsWeb proxy for fetching the marketing-site canonical HTML
apps/web/src/i18n/dictionaries/{en,he,ru}.jsonlegal.* keys for checkbox labels, errors, “Documents updated” banner copy
apps/web/src/app/[lang]/(protected)/accept-terms/page.tsxUses server isRequired && requiresReconsent; folds member terms into the core required legal choice and keeps conditional external acknowledgement separate
apps/marketingCanonical member terms (member-terms) and external-payment responsibility (external-payment-responsibility) in Hebrew root, /en, and /ru; platform Terms remain a separate owner-only B2B document

Mobile (taikan-mobile)

PathResponsibility
src/components/legal/legal-consent-form.tsxDynamic server-required document list; one required member checkbox includes privacy, health acknowledgement, and member terms; only conditional external-payment responsibility remains a separate required control. Optional analytics/replay remains unchecked and separately disclosed
src/hooks/use-legal.tsCompatibility document/status types and canonical document URL mapping, including member terms/external responsibility
src/lib/analytics.tsConsent-gated PostHog construction and explicit replay masking/log/network settings
app/accept-terms.tsxPasses server-required types into the shared consent form

i18n hot keys

legal.acceptTos, legal.acceptPrivacy, legal.viewDocument, legal.updatedBanner, legal.submit, plus localized unified member-agreement and separate external-payment-acknowledgement labels. Display fitness_waiver as Fitness & Health Acknowledgement without changing its type/slug or waiving mandatory rights. Analytics consent remains independent.